2012-02-22 4 views
3

в моем приложении у меня есть «биение» функциональность, которая в настоящее время реализуется в длинной бегущей нити следующим образом (псевдокод):Heartbeat реализация с Thread.Sleep()

while (shouldBeRunning) 
{ 
    Thread.Sleep(smallInterval); 

    if (DateTime.UtcNow - lastHeartbeat > heartbeatInterval) 
    { 
     sendHeartbeat(); 
     lastHeartbeat = DateTime.UtcNow; 
    } 
} 

Теперь, случается, что когда мое приложение проходит некоторое интенсивное время процессора (несколько минут тяжелых вычислений, в которых процессор занимает 90%), сердечные удары задерживаются, даже если smallInterval < < heartbeatInterval.

Чтобы хрустить некоторые цифры: heartbeatInterval - 60 секунд, lastHeartbeat - 0,1 секунды, а сообщенная задержка может достигать 15 секунд. Таким образом, по моему мнению, это означает, что Sleep (10) может длиться, как Sleep (15000), когда процессор очень занят.

Я уже пробовал устанавливать приоритет потока как AboveNormal - как я могу улучшить свой дизайн, чтобы избежать таких проблем?

+4

Почему бы не использовать таймер для этого? –

+0

Плохой дизайн, в основном :) Я, безусловно, перехожу к более надежному решению (и таймеры - самая очевидная вещь), но в этот момент мне любопытно поведение. – Andrea

+0

@ Andrea - исправить ваш дизайн. Проблема, с которой вы столкнулись, является причиной создания класса Timer. Обратите внимание, что вы по-прежнему будете во власти .NET Scheduler. –

ответ

2

К сожалению, Windows не является операционной системой реального времени, поэтому существует несколько гарантий относительно того, когда выполняются потоки. В Thread.Sleep() только расписано самое раннее время, когда поток должен быть разбужен в следующий раз, то есть до ОС, чтобы разбудить поток, когда есть свободное время. Точные критерии для пробуждения спящего потока, вероятно, не документированы, поэтому команда ядра Window может изменить реализацию по своему усмотрению.

Я не уверен, что объекты Timer будут решать это, так как поток пульса по-прежнему должен быть активирован после истечения таймера.

Одним из решений является повышение приоритета потока сердечных сокращений, чтобы он получал возможность выполнять чаще.

Тем не менее, сердечные сокращения обычно используются для определения того, что подсистема застряла в бесконечном цикле, например, поэтому они обычно имеют низкий приоритет. Когда у вас есть секция интенсивной работы с процессором, выполните Thread.Sleep (0) в ключевых точках, чтобы обеспечить возможность выполнения потоков с меньшим приоритетом.

4

Есть ли причина, по которой вы не можете использовать Таймер? Есть три вида, которые вы можете использовать, и я обычно иду за System.Timers.Timer. В следующей статье рассматриваются различия, хотя:

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

По существу таймеры позволяют настроить таймер с периодическим интервалом и огнестойкость событие всякий раз, когда этот период клещей прошлое. Затем вы можете подписаться на мероприятие с делегатом, который звонит sendHeartbeat().

Таймеры должны служить вам лучше, так как они не будут затронуты загрузкой процессора так же, как ваш спальный поток. Преимущество состоит в том, что он немного опережает код (настройка таймера очень проста и читаема), и у вас не будет запасной нитки.

2

Кажется, вы пытаетесь изобрести один из классов таймера.

Как насчет использования System.Timers.Timer?

var timer = new System.Timers.Timer(smallInterval); 
timer.Elapsed += (s, a) => sendHeartbeat; 
timer.Enabled = true; 

Одна из проблем здесь может быть, на догадку, как часто ваш поток получает запланированной, когда процессор находится под нагрузкой. Реализация вашего таймера по сути является однопоточной и блокирует. Переход к одному из таймеров инфраструктуры должен облегчить это, поскольку (например, с использованием приведенного выше таймера) прошедшее событие возникает в потоке пула потоков, которого много.