У меня работает несколько потоков (приложение C#, работающее на IIS), которым все должны взаимодействовать с одним и тем же сервером MQ. Чтобы минимизировать сетевой трафик, мне нужно отправлять бэкэнд-запрос только тогда, когда есть работа, которую нужно выполнить. Будет один поток, который будет отслеживать, нужно ли выполнить работу, и он должен уведомить другие потоки о том, что они также должны начать обработку. Текущее решение предполагает, что поток монитора устанавливает глобальную переменную и имеет цикл других потоков и проверяет это, то есть в потоке монитора:
CheckIfWorkAvailable() {
while(true) {
if (queue.Empty != true) {
workToBeDone = true;
}
}//end while loop
}
а затем в рабочих потоках:
DoWork() {
while(true) {
if (workToBeDone == true) {
//do work...
}
else {
Thread.Sleep(x seconds)
}
}//end while loop
}
Может ли поток монитора уведомлять рабочие потоки, когда есть работа, вместо того, чтобы они просто зацикливались и спали? Рабочие потоки также устанавливают счетчик, указывающий, что они работают, и уменьшают его, когда их работа завершена, поэтому для флага workToBeDone можно установить значение false.





Посмотрите WaitHandle и его нисходящие классы. СобытиеWaitHandle может удовлетворить ваши потребности.
http://msdn.microsoft.com/en-us/library/yy12yx1f(VS.80).aspx
Вы можете использовать AutoReset Events
В вашем сценарии также может быть возможно напрямую использовать класс ThreadPool. Это означает, что вам не нужно настраивать потоки, которые вы будете использовать, а также позволяет настраивать потоки в зависимости от выполняемой работы.
Если вы используете CTP в своих проектах, возможно, вы захотите проверить ОСАГО, поскольку это более продвинутые функции синхронизации и постановки задач.
Так же, как классы WaitHandle, указанные Кентом, простые Monitor.Wait и Monitor.Пульс / PulseAll могут сделать это легко. Они «легче», чем дескрипторы событий, хотя и несколько примитивнее. (Вы не можете ждать на нескольких мониторах и т. д.)
У меня есть пример этого (как очередь потребителя производителя) в моем разделить статью.
Используйте ManualResetEvent для случаев, когда вы хотите, чтобы все рабочие потоки продолжались при достижении состояния (похоже, что вы здесь хотите). Используйте AutoResetEvent в тех случаях, когда вы хотите сигнализировать только одному работнику каждый раз, когда какая-то работа становится доступной. Используйте Semaphore, если вы хотите разрешить выполнение определенного количества потоков. Практически никогда не используйте глобальную переменную для этого типа вещей, а если вы это сделаете, пометьте ее как изменчивую.
Будьте осторожны в этой ситуации. Вы не хотите, чтобы происходили «конвои блокировок», потому что вы освобождаете всех рабочих, чтобы они попадали в очередь сразу, каждый раз, когда освобождается отдельный элемент, только для того, чтобы снова ждать.
Я как раз собирался сказать то же самое. Мы использовали AutoResetEvent для подобной синхронизации потоков в коде, который я написал некоторое время назад.