How to execute 2 consecutive commands in a thread without a context switch occurring?
I have a C# program, which has an "Agent" class. The program creates several Agents, and each Agent has a "run()" method, which executes a Task (i.e.: Task.Factory.StartNew()...).
Each Agent performs some calculations, and then needs to wait for all the other Agents to finish their calculations, before proceeding to the next stage (his actions will be based according to the calculations of the others). In order to make an Agent wait, I have created a CancellationTokenSource (named "tokenSource"), and in order to alert the program that this Agent is going to sleep, I threw an event. Thus, the 2 consecutive commands are:(1) OnWaitingForAgents(new EventArgs());
(2) tokenSource.Token.WaitHandle.WaitOne();
(The event is caught by an "AgentManager" class, which is a thread in itself, and the 2nd command makes the Agent Task thread sleep until a signal will be received for the Cancellation Token).
Each time the above event is fired, the AgentManager class catches it, and adds +1 to a counter. If the number of the counter equals the number of Agents used in the program, the AgentManager (which holds a reference to all Agents) wakes each one up as follows:
agent.TokenSource.Cancel();
Now we reach my problem: The 1st command is executed asynchronously by an Agent, then due to a context switch between threads, the AgentManager seems to catch the event, and goes on to wake up all the Agents. BUT - the current Agent has not even reached the 开发者_Go百科2nd command yet ! Thus, the Agent is receiving a "wake up" signal, and only then does he go to sleep, which means he gets stuck sleeping with no one to wake him up! Is there a way to "atomize" the 2 consecutive methods together, so no context switch will happen, thus forcing the Agent to go to sleep before the AgentManager has the chance to wake him up?
The low-level technique that you are asking about is thread synchronisation. What you have there is a critical section (or part of one), and you need to protect access to it. I'm surprised that you've learned about multithreaded programming without having learned about thread synchronisation and critical sections yet! It's essential to know about these things for any kind of "low-level" multithreaded programming.
Maybe look into Parallel.Invoke or Parallel.For in .NET 4, which allows you to execute methods in parallel and wait until all parallel methods have been invoked.
http://msdn.microsoft.com/en-us/library/dd992634.aspx
Seems like that would help you out a lot, and take care of all the queuing for you.
humm... I don't think it's good idea (or even possible) develop software in .NET worrying about context switches, since neither Windows or .NET are real time. Probably you have another kind of problem in that code.
I've understood that you simply run all your agents in parallel, and you want to wait till all of them have finished to go to the next stage. You can use several techniques to accomplish that, the easiest one would be using Monitor.Wait(Object monitor)
and Monitor.PulseAll(Object monitor)
.
In the task library there are several things to do it as well. As @jishi has pointed out, you can use the Parallel
flavours, or spawn a lot of Task
s and then wait for all with the Task.WaitAll(Task[] tasks)
method.
Each time the above event is fired, the AgentManager class catches it, and adds +1 to a counter.
How are you adding 1 to that counter and how are you reading it? You should use Interloked.Increment
to ensure an atomic operation, and read it in a volatile operation with Thread.VolatileRead
for example, or simply put it in a lock statement.
精彩评论