0

我有一个 C# 程序,它有一个“代理”类。该程序创建了几个Agent,每个Agent都有一个“ run() ”方法,它执行一个Task(即:Task.Factory.StartNew() ...)。
每个 Agent 进行一些计算,然后需要等待所有其他 Agent 完成计算,然后才能进入下一个阶段(他的动作将根据其他 Agent 的计算)。
为了让 Agent 等待,我创建了一个 CancellationTokenSource(命名为“tokenSource”),并且为了提醒程序这个 Agent 将要休眠,我抛出了一个事件。因此,两个连续的命令是:

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

(该事件被“AgentManager”类捕获,该类本身就是一个线程,第二个命令使代理任务线程休眠,直到收到取消令牌的信号)。

每次触发上述事件时,AgentManager 类都会捕获它,并将 +1 加到计数器上。如果计数器的数量等于程序中使用的 Agent 的数量,AgentManager(持有对所有 Agent 的引用)按如下方式唤醒每个 Agent:

agent.TokenSource.Cancel();

现在我们遇到了我的问题:第一个命令由代理异步执行,然后由于线程之间的上下文切换,代理管理器似乎捕获了事件,并继续唤醒所有代理。但是-当前的代理甚至还没有达到第二个命令!因此,代理正在接收“唤醒”信号,然后他才进入睡眠状态,这意味着他被困在没有人唤醒他的情况下!有没有办法将两个连续的方法“原子化”在一起,所以不会发生上下文切换,从而在 AgentManager 有机会唤醒他之前强制 Agent 进入睡眠状态?

4

3 回答 3

1

您要询问的低级技术是线程同步。您所拥有的是一个关键部分(或其中的一部分),您需要保护对它的访问。我很惊讶您已经了解了多线程编程,但还没有了解线程同步和临界区!对于任何类型的“低级”多线程编程,了解这些事情都是必不可少的。

于 2011-04-12T12:12:30.317 回答
0

也许查看 .NET 4 中的 Parallel.Invoke 或 Parallel.For,它允许您并行执行方法并等待所有并行方法被调用。

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

似乎这会对您有很大帮助,并为您处理所有排队问题。

于 2011-04-09T11:47:24.723 回答
0

嗯...我认为在 .NET 中开发担心上下文切换的软件不是一个好主意(甚至可能),因为 Windows 或 .NET 都不是实时的。可能您在该代码中有另一种问题。

我理解您只是并行运行所有代理,并且您希望等到所有代理都完成后才能进入下一阶段。您可以使用多种技术来实现这一点,最简单的一种是使用Monitor.Wait(Object monitor)and Monitor.PulseAll(Object monitor)

在任务库中,还有几件事要做。正如@jishi 指出的那样,您可以使用这些Parallel口味,或者产生很多s ,然后使用该方法Task等待所有内容。Task.WaitAll(Task[] tasks)

每次触发上述事件时,AgentManager 类都会捕获它,并将 +1 加到计数器上。

你是如何将 1 加到那个计数器上的,你是如何读取它的?您应该使用Interloked.Increment来确保原子操作,并在 volatile 操作中读取它,Thread.VolatileRead例如,或者简单地将其放在 lock 语句中。

于 2011-04-12T10:15:45.277 回答