C#多线程编程中的锁系统(三)
本章主要说下基于内核模式构造的线程同步方式,事件,信号量。 目录 一:理论 一:理论 我们晓得线程同步可分为,用户模式构造和内核模式构造。 内核模式构造:是由windows系统本身使用,内核对象进行调度协助的。内核对象是系统地址空间中的一个内存块,由系统创建维护。 内核对象为内核所拥有,而不为进程所拥有,所以不同进程可以访问同一个内核对象,如进程,线程,作业,事件,文件,信号量,互斥量等都是内核对象。 而信号量,互斥体,事件是windows专门用来帮助我们进行线程同步的内核对象。 对于线程同步操作来说,内核对象只有2个状态, 触发(终止,true)、未触发(非终止,false)。 未触发不可调度,触发可调度。 用户模式构造:是由特殊CPU指令来协调线程,上节讲的volatile实现就是一种,Interlocked也是。 也可称为非阻塞线程同步。 二:WaitHandle 在windows编程中,我们通过API创建一个内核对象后会返回一个句柄,句柄则是每个进程句柄表的索引,而后可以拿到内核对象的指针、掩码、标示等。 而WaitHandle抽象基类类作用是包装了一个windows内核对象的句柄。我们来看下其中一个WaitOne的函数源码(略精简)。
复制代码 代码如下: public virtual bool WaitOne(TimeSpan timeout) { return WaitOne(timeout,false); } [System.Security.SecuritySafeCritical] // auto-generated WaitAll 和WaitAny 调用win32中,waitformultipleobjectsEx函数。 SignalAndWaitOne 调用win32中,signalandwait函数。 调用api带ex都是设置超时的。 如果我们在c#中不传,默认是-1 表示无限期等待。 其中SafeWaitHandle字段,包含了一个win32内核对象句柄。 理解了WaitHandle其他都好办了,我们来看下它的派生类型。 复制代码 代码如下: WaitHandle |――EventWaitHandle 事件构造。 |――AutoResetEvent |――ManualResetEvent |――Semaphore 信号量构造。 |――Mutex 互斥体构造。 其中Semaphore和mutex第一章已经说过了,下面来看看其他的。 三:AutoResetEvent 使用示例如下,有简单注释。 关于描述,尽量贴近系统自身术语。 复制代码 代码如下: static void Main(string[] args) { //AutoResetEvent example //AutoResetEvent 通知正在等待的线程已发生的事件。 AutoResetEvent waitHandler = new AutoResetEvent(false);//false 即非终止,未触发。 new Thread(() => { waitHandler.WaitOne(); //阻塞当前线程,等待底层内核对象收到信号。 Console.WriteLine("接收到信号,开始处理。"); }).Start(); }).Start(); WaitOne 阻塞线程,非自旋。 Set() 发出一个信号后,设置事件状态为false。 这本应该是2步的操作,AutoResetEvent.set()函数,给2步一起自动做了,很方便。 四:ManualResetEvent 这个和上面基本一样,从字面来说需要手动重置状态,我们来看例子。 复制代码 代码如下: ManualResetEvent manualWaitHandler = new ManualResetEvent(false);//false 即非终止,未触发。 new Thread(() => { manualWaitHandler.WaitOne(); //阻塞当前线程对象,等待信号。 Console.WriteLine("接收到信号,开始处理。"); manualWaitHandler.Reset(); //手动 设置事件对象状态为非终止状态,false。 }).Start(); Thread.Sleep(2000); 这2则区别很小,其实是系统Api的区分,不是net类库实现的。 在Win32Native类中,我可以看到KERNEL32 api 有这么个参数isManualReset。 复制代码 代码如下: [DllImport(KERNEL32,SetLastError=true,CharSet=CharSet.Auto,BestFitMapping=false)] [ResourceExposure(ResourceScope.Machine)] // Machine or none based on the value of "name" internal static extern SafeWaitHandle CreateEvent(SECURITY_ATTRIBUTES lpSecurityAttributes,bool isManualReset,bool initialState,String name); 五:总结 基于内核模式构造的同步步骤是: 托管代码->用户模式代码->内核模式代码。 用户模式构造, 是利用CPU特殊指令,进行原子操作。 用户模式代码,如图。 是指 托管代码调用 win32代码 这一层, 之后在调内核模式代码。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |