主要使用Monitor类,对一个对象进行等待和通知的操作
static void Main(string[] args)
{
//Task启动等待对象
object taskStartSyncRoot = new object();
//多线程等待对象
object syncRoot = new object();
//多线程全部进入等待状态对象
object parallelStartSyncRoot = new object();
lock (taskStartSyncRoot)
{
Task.Factory.StartNew(() =>
{
lock (parallelStartSyncRoot)
{
lock (taskStartSyncRoot)
{
//通知Task已经启动完毕
Monitor.Pulse(taskStartSyncRoot);
}
Console.WriteLine("Wait all parallel task started.");
//等待所有并行任务已经进行等待状态,并释放parallelStartSyncRoot锁
Monitor.Wait(parallelStartSyncRoot);
lock (syncRoot)
{
//通知所有并行任务syncRoot已经释放
Monitor.PulseAll(syncRoot);
Console.WriteLine("All syncRoot waiter notified.");
}
}
});
//等待Task启动完毕,并释放taskStartSyncRoot对象锁
Monitor.Wait(taskStartSyncRoot);
}
//并行等待任务计数器,当该计数器为10时,则通知所有并行任务已经进入等待状态
int counter = 0;
Parallel.For(0, 10, (i) =>
{
lock (syncRoot)
{
//使用原子锁增加counter,当计数器为10时代表所有并行任务已经启动
if (Interlocked.Increment(ref counter) == 10)
{
lock (parallelStartSyncRoot)
{
//通知并行任务已经全部启动,并释放parallelStartSyncRoot锁
Monitor.Pulse(parallelStartSyncRoot);
}
}
Console.WriteLine(string.Format("[{0}] Waiting For syncRoot notify.", i));
//等待syncRoot通知,并释放syncRoot锁
Monitor.Wait(syncRoot);
Console.WriteLine(string.Format("[{0}] syncRoot notify received.", i));
}
});
Console.Read();
}
该程序是个多线程的应用,程序的逻辑将会严格按照以下顺序执行
(1)[主线程] 启动Task线程,等待taskStartSyncRoot,暂时释放syncRoot锁
(2)[TASK线程] 锁住parallelStartSyncRoot 和 taskStartSyncRoot(这里会等待主线程进入Wait状态),通知taskStartSyncRoot已经启动
(3)[TASK线程] 等待parallelStartSyncRoot,暂时释放parallelStartSyncRoot锁
(4)[Parallel子线程] Parallel并行任务启动,并且等待syncRoot,暂时释放syncRoot锁
(5)[最后一个Parallel子线程] 通知parallelStartSyncRoot已经全部启动
(6)[TASK线程] 等待锁syncRoot
(7)[最后一个Parallel子线程] 等待syncRoot,这时会暂时释放syncRoot锁
(8)[TASK线程] 获得syncRoot锁,并且通知(Monitor.PulseAll)所有syncRoot等待者(所有并行任务)。
程序的执行结果:
总结:要理解该多线程程序,必须要理解这三个锁对象的操作,以及通知机制的应用,从而可以让Task和多个并行任务有序的进行执行,大家在这里需要掌握几个知识点:
(1)在Monitor.Wait对象时必须获得目标对象的锁,以确保进入临界状态
(2)Monitor.Wait方法调用时,会将目标对象锁释放,在Wait完成时会重新获得该锁