Как выполнить 2 последовательные команды в потоке без переключения контекста? - PullRequest
0 голосов
/ 09 апреля 2011

У меня есть программа на C #, в которой есть «Агент» класс. Программа создает несколько агентов, и у каждого агента есть метод " run () ", который выполняет задачу (т. Е. Task.Factory.StartNew () ...).
Каждый агент выполняет некоторые вычисления, а затем должен дождаться, пока все другие агенты завершат свои вычисления, прежде чем перейти к следующему этапу (его действия будут основаны на расчетах других).
Чтобы заставить агента ждать, я создал CancellationTokenSource (названный «tokenSource»), и чтобы предупредить программу о том, что этот агент будет спать, я вызвал событие. Таким образом, 2 последовательные команды:

(1) OnWaitingForAgents(new EventArgs());
(2) tokenSource.Token.WaitHandle.WaitOne();

(Событие перехватывается классом «AgentManager» , который сам по себе является потоком, а 2-я команда переводит поток задач агента в спящий режим до получения сигнала для токена отмены).

Каждый раз, когда указанное событие инициируется, класс AgentManager перехватывает его и добавляет +1 к счетчику. Если номер счетчика равен количеству агентов, используемых в программе, AgentManager (который содержит ссылку на все агенты) активирует каждого из них следующим образом:

agent.TokenSource.Cancel();

Теперь мы подошли к моей проблеме: 1-я команда выполняется асинхронно Агентом, затем из-за переключения контекста между потоками AgentManager, похоже, перехватывает событие и продолжает активировать всех Агентов. НО - текущий Агент еще даже не достиг 2-й команды! Таким образом, Агент получает сигнал «проснуться», и только тогда он ложится спать, а это значит, что он застревает во сне, и никто его не разбудит! Есть ли способ «атомизировать» два последовательных метода вместе, поэтому переключение контекста не произойдет, что заставит Агента перейти в спящий режим до того, как AgentManager сможет его разбудить?

Ответы [ 3 ]

1 голос
/ 12 апреля 2011

Низкоуровневая техника, о которой вы спрашиваете, - это синхронизация потоков.У вас есть критический раздел (или его часть), и вам нужно защитить доступ к нему.Я удивлен, что вы узнали о многопоточном программировании, еще не узнав о синхронизации потоков и критических секциях!Об этом необходимо знать для любого вида «низкоуровневого» многопоточного программирования.

0 голосов
/ 12 апреля 2011

гм ... Я не думаю, что это хорошая идея (или даже возможно) разрабатывать программное обеспечение в .NET, беспокоясь о переключении контекста, поскольку ни Windows, ни .NET не работают в реальном времени. Возможно, у вас есть другая проблема в этом коде.

Я понял, что вы просто запускаете все свои агенты параллельно и хотите подождать, пока все они не закончат, чтобы перейти к следующему этапу. Вы можете использовать несколько методов для достижения этой цели, самый простой из них будет использовать Monitor.Wait(Object monitor) и Monitor.PulseAll(Object monitor).

В библиотеке задач также есть несколько вещей, чтобы сделать это. Как указал @jishi, вы можете использовать вкусы Parallel или порождать много Task с, а затем ждать всех с помощью метода Task.WaitAll(Task[] tasks).

Каждый раз, когда указанное событие происходит, класс AgentManager ловит его и добавляет +1 к счетчику.

Как вы добавляете 1 к этому счетчику и как вы его читаете? Вы должны использовать Interloked.Increment, чтобы обеспечить атомарную операцию, и прочитать ее в энергозависимой операции, например, с Thread.VolatileRead, или просто поместить ее в оператор блокировки.

0 голосов
/ 09 апреля 2011

Может быть, посмотрите на Parallel.Invoke или Parallel.For в .NET 4, который позволяет вам выполнять методы параллельно и ждать, пока все параллельные методы будут вызваны.

http://msdn.microsoft.com/en-us/library/dd992634.aspx

Похоже, это очень вам поможет и позаботится обо всех очередях для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...