多线程编程学习笔记(四)
同步
实现同步的3种方法:
1、Thread.Join()
2、WaitHandle
//使用自动事件
AutoResetEvent asyncOpIsDone = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(MyAsyncOperation),asyncOpIsDone);
asyncOpIsDone.WaitOne();//asyncOpIsDone自动被复位
ThreadPool.QueueUserWorkItem(new WaitCallback(MyAsyncOperation),asyncOpIsDone);
asyncOpIsDone.WaitOne();//asyncOpIsDone自动被复位
//使用手工代码
ManualResetEvent masyncOpIsDone = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(MyAsyncOperation),masyncOpIsDone);
masyncOpIsDone.WaitOne();//asyncOpIsDone自动被复位
//masyncOpIsDone仍处于有信号状态
//必须手工复位
masyncOpIsDone.Reset(); //如果该代码注释掉,则主线程不会等待第2个子线程结束。
ThreadPool.QueueUserWorkItem(new WaitCallback(MyAsyncOperation),masyncOpIsDone);
masyncOpIsDone.WaitOne();//asyncOpIsDone自动被复位
3、Monitor
//下面实现同步的例子
using System;
using System.Threading;
namespace AppThreadDemo
{
public class Buffer
{
const int size = 1;
char[] buffer = new char[size];//临界资源
//n缓冲区的字符数
//head队列头
//tail队列尾
int n=0,head = 0, tail =0 ;
public void Put(char ch)
{
Console.WriteLine("Put 开始");
lock(this)
{
n++;//放一个字符
while(n> size){//如果n>size说明缓冲区满,故期待读线程取数据
Console.WriteLine("Put Monitor.Wait");
Monitor.Wait(this);
}
buffer[tail]=ch;
tail = (tail+1) % size ;
Console.WriteLine("Put tail={0}\tbuffer={1}\tn={2}",tail,buffer[tail],n);
if (n <=0) //如果缓冲区为空,则通知所有等待线程
{
Console.WriteLine("Put 通知等待的所有线程");
Monitor.PulseAll(this);
}
}
}
public char Get()
{
char ch;
Console.WriteLine("Get 开始");
lock(this)
{
n--;//先取一个字符
while(n<0)//如果缓冲区为空,则等待写线程写入数据
{
Console.WriteLine("Get Monitor.Wait");
Monitor.Wait(this);
}
ch = buffer[head];
head = (head + 1) % size;
Console.WriteLine("Get tail={0}\tbuffer={1}\tn={2}",tail,buffer[tail],n);
if(n>=size)//如果缓冲区满了,则通知所有等待线程
{
Console.WriteLine("Get 通知等待的所有线程");
Monitor.PulseAll(this);
}
return ch;
}
}
}
class App
{
static public void bufferRead()
{
Object o = AppDomain.CurrentDomain.GetData("Buffer");
if(o!=null)
{
Buffer buffer = (Buffer)o;
for(int i=0;i<8;i++)
{
Console.WriteLine("读线程\t{0}读到字符\t{1}",Thread.CurrentThread.GetHashCode(),buffer.Get());
}
}
Console.WriteLine("读取结束");
}
static public void bufferWrite()
{
Object o = AppDomain.CurrentDomain.GetData("Buffer");
char[] msg ={'A','B','C','D','E','F','G','H','I','J','1','2'};
if(o!=null)
{
Buffer buffer = (Buffer)o;
for(int i=0;i<msg.GetLength(0);i++)
{
Console.WriteLine("写线程\t{0}写字符\t{1}",Thread.CurrentThread.GetHashCode(),msg[i]);
buffer.Put(msg[i]);
}
}
Console.WriteLine("写结束");
}
static public void demoBuffer()
{
Buffer buffer = new Buffer();
AppDomain.CurrentDomain.SetData("Buffer",buffer);
Thread threadReader = new Thread(new ThreadStart(App.bufferRead));
Thread threadWriter = new Thread(new ThreadStart(App.bufferWrite));
threadReader.Start();
threadWriter.Start();
threadWriter.Join();
threadReader.Join();
}
static int Main(string[] args)
{
demoBuffer();
return 0;
}
}
}
3种方法的总结:
A、Thread.Join用以等待特定的线程实例thread结束,常用以主线程和子线程之间的同步。
B、AutoResetEvent和ManualResetEvent用事件信号量的方式实现多个线程之间的同步。
C、Monitor要和Lock/SyncLock语句配合才能实现同步。
《.net核心技术-原理与架构》