Синхронизация нескольких потоков в .net 4 - PullRequest
2 голосов
/ 29 декабря 2011

Справочная информация: я работаю над приложением, в котором уже разработана система потоков.Это далеко от оптимального, но я не могу переделать это в настоящее время.Он не использует ни одну из более новых конструкций потоков из .net, только базовые Thread объекты и объекты, обертывающие логику обработки потока.

Общая настройка этого: (есть две группы, иликатегории потоков прямо сейчас)

  • Главный поток приложения (главная тема), который порождает рабочие потоки.

  • Рабочие потоки.Каждый из них имеет объект Thread и рабочий объект, который выполняет всю обработку / обрабатывает границу между потоками и т. Д. Каждый поток выполняет задания, а каждое задание имеет JobTypeID.

Мне нужно ввести третий тип потока, один для управления рабочими.Эти управляющие сообщения будут поступать из веб-службы wcf (поэтому этот поток обрабатывается неявно).

Управляющими сообщениями являются: {Pause / Resume, List-of-IDs}

Моя цель:

Я пытаюсь выяснить, как лучше всего синхронизировать эти потоки, чтобы, если поток обрабатывал задание, и приходило сообщение о приостановке всех заданий этого JobTypeID, он должен блокироваться до отправки резюме (для этого идентификатора).Уловка здесь в том, что во время отправки сообщения никакие соответствующие задания не могут быть обработаны, поэтому не нужно предпринимать немедленных действий, и у меня также нет списка рабочих объектов, поэтому я не могу простопереберите каждого работника и выполните if-match-then-pause.

Актуальный вопрос (обобщенно) Что бы вы, ребята, посоветовали сделать для синхронизации набора рабочих потоков, spawner / managerпоток и набор контрольных потоков?

вещи, которые я пробовал

Один из подходов заключается в хранении коллекции ManualResetEvent объектов, по одному на JobTypeID и сигнализировать и ждать их в соответствии с входящими сообщениями.Что вы думаете об этом подходе?Я не могу найти какую-либо информацию о передовых методах или затратах на память / обработку для наличия более 100 дескрипторов ожидания в процессе.

Другой подход состоит в том, чтобы иметь один объект, для которого все потоки будут ожидать,синхронизированная коллекция JobTypeIDs, которая должна ждать.У меня были некоторые проблемы с этим подходом.Использование ManualResetEvent означает, что если я возобновляю один идентификатор задания, но другие ожидают, я должен сделать set (); reset ();, и это вызывает некоторые условия гонки (даже если я пытаюсь сделать WaitHandle.SignalAndWait (x, x)) Наконец, я нашел решение, использующее Monitor.PulseAll (), которое работает.

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

Также, извините за длинный вопрос и спасибо за чтение!

1 Ответ

2 голосов
/ 29 декабря 2011

Создать ConcurrentDictionary<JobTypeId, ManualResetEvent>.Обычно в словаре не будет записи для JobTypeId.Такая запись существует только тогда, когда предполагается, что этот тип задания должен быть заблокирован.

Когда предполагается, что этот тип задания должен быть заблокирован, создайте ManualResetEvent, который не имеет сигнала, и добавьте его в словарь.с ключом, являющимся JobTypeId, который должен быть заблокирован.

Рабочие потоки, таким образом, имеют цикл, который выглядит следующим образом:

while (still_have_work_to_do)
{
    ManualResetEvent mevent;
    if (PauseDictionary.TryGetValue(myJobTypeId, out mevent))
    {
        // wait until the event is signaled.
        mevent.WaitOne();
    }

    // Do more processing.
}

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

Нет особых проблем с сотнями WaitHandle объектов в одном процессе.Группа Monitor объектов может потребовать меньше системных ресурсов, но помните, что Monitor (или lock) действительно является устройством взаимного исключения.Вы можете делать глупости, чтобы заставить его действовать как WaitHandle в некоторых отношениях, но методы неочевидны, что приведет к сложному для понимания и хрупкому коду.

...