Windows同步对象

Windows同步对象小结

Event:
               内核对象,跨进程使用时,不能共享句柄,在调用CreateEvent创建命名事件后,用OpenEvent获得句柄后使用
 
Critical Section:
               不是内核对象,不能跨进程使用,不能设置等待时间,也无法获知进入临界区的线程生死状态

Mutex:
               内核对象,可跨进程使用,等待时可设定超时。  拥有权属于最后一个进行等待操作的线程,在拥有Mutex的线程结束前如果没有调用ReleaseMutex(),这个Mutex就被
舍弃,其它线程调用Wait..时,将会返回WAIT_ABANDONED_0
 
Semaphore:
               内核对象,可控制多个需要同步的资源
 
同步保护机制的一些明显的行为特征,而这些行为特征,也是我们再写程序时经常会碰到的。

       以下我们所讨论的这些行为特征,是对并发的进/线程之间的同步保护机制的一般描述,本文用windows平台作为一个典型的例子。 基于这一些行为特征,对本文提及的这四种同步对象做一个分类。
另外,在这里,我们把这四种同步对象,统统称为“锁”,以便于接下来的讨论。
第一、保护与同步。
        在这里要强调的是:保护与同步是两个不同的概念。而我们经常会混合这两个概念。保护是指在多线程的环境下对共享资源的保护。这样的共享资源大多数情况下是一段内存块,它会被很多线程试图访问和修改。而同步更多的强调的是线程之间的协作,协同工作是需要同步支持的。
基于这一性质,我们可以看出:Critical Section对象其本质更多的强调的是保护,而Event对象、Mutex对象与Semaphore对象更多的强调的是同步。不过,这样的区别,只是概念上的区别,其本身不会对程序本身产生影响。
第二、锁的等待超时
       在开发并发的多进/线程程序时,为了避免死锁之类的问题,引入了“等超时“的概念,即当一个线程需要获得一个锁来执行某些代码的时候,它可以在所等待的锁上设置超时值。如果在确定的时间(超时值)内无法获得该锁,它可以选择放弃执行该段代码的权利,这样可以在一定程度上避免出现死锁的问题。这就是锁的等待超时的基本含义。基于这一行为特征,我们来对上面四种同步对象做一个划分:Critical Section对象是无法设置等待超时的,而其他三个对象则可以设置等待超时。从这一点来讲,在使用Critical Section对象时,由于在等待进入关键代码段时无法设置等待超时,很容易造成死锁。
第三、线程锁与进程锁
        这里所说的线程锁指的是该锁只在一个进程的所有线程中可见,而进程锁指的是该锁可以被不同的进程所访问,可用于进程间的同步与互斥。当然进程锁仍然可以被用于同一个进程的不同线程之间的同步与互斥。进程锁的概念是大于线程锁的。基于这一特点划分的话,Critical Section对象是线程锁,而其他三个对象是进程锁。这一点从本质上来分析,Critical Section对象是用户态模式下面实现线程同步的方法,而其他三个对象均是内核对象。内核对象机制的适应性远远优于用户方式机制。实际上,内核对象机制的唯一不足之处在于它的速度比较慢,这是因为当调用内核机制对象时,必须从用户方式转到内核方式。这样的转换需要付出很大的代价,是一件很费时的操作。在X86平台上,这样往返一次需要占用1000个CPU周期(这并不包括执行内核方式的代码)。当然需要注意的是:使用Critical Section对象并不意味着线程不会陷入核心态执行。当一个线程试图进入另一个线程拥有的关键代码段时,该线程就会进入等待状态。这意味着:该线程必须从用户态转为核心态。(为了提高这一方面的性能,Microsoft将循环锁的概念纳入到了Critical Section对象中,该线程可以有选择地不进入核心态等待.具体请参阅MSDN)
第四、锁的递归特质
        所谓递归锁指的是当一个线程拥有一个同步锁时,而递归地想再次取得该锁.如果这次获得操作不会阻塞当前线程的执行,则称该锁为递归锁.递归锁主要是在"保护"的概念上提出的,而"保护"概念下的锁包括Critical Section对象和Mutext 对象.这两种锁在Windows平台上都是递归锁。需要注意的是:调用线程获得几次递归锁必须释放几次递归锁。
第五、读写锁
       读写锁允许高效的并发的访问多线程环境下的共享资源。对于一种共享资源,多个线程可以获得读锁,共享地读该共享资源。而在同一时刻,只允许一个线程拥有写锁改变该共享资源.这就是读写锁的概念。很遗憾的是在Windows平台上没有这样的读写锁,你需要自己去实现。
对以上总结如图:

Windows同步对象_第1张图片
Futher Read:
         个人认为,如果你想深入研究多线程的同步机制,ACE是一个绝佳的教材,在这里,你会看到什么是Scoped Lock, 读写锁如何实现等等。
----------------------------------------------------------------------------------------------------------------

同步对象
Windows共设置了4种主要的同步对象,分别是临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)和事件(Event)。MFC封装了它们,分别是类CCriticalSection、CMutex、CSemaphore和CEvent,它们都以CSyncObject为基类。

1、临界区
(1)创建:CCriticalSection myCriticalSection;
(2)对临界区加锁:myCriticalSection.Lock();
(3)解锁:myCriticalSection.UnLock();


2、互斥对象
它不仅可以在同一进程的线程之间实现资源的安全共享,而且可以在不用进程的线程之间实现资源的安全共享。
(1)创建:CMutex myMutex;
(2)创建一个CSingleLock对象:CSingleLock singleLock(&myMutex);
(3)得到Mutex对象:singleLock.Lock();
(4)如果其他线程已经拥有了该Mutex对象,那么系统会把该线程挂起来。
(5)释放:singleLock.UnLock();


3、信号量对象
允许多个线程同时访问一个受保护的资源。
(1)创建:CSemaphore myCSemaphore;
CSemaphore=new CSemaphore(5,5);
其中第一个参数为计数器的初始值,第二个参数为计数器的最大值。
(2)使用:CSingleLock singleLock(&myCSemaphore);
(3)减少CSemaphore对象的计数值:singleLock.Lock();
(4)释放CSemaphore对象:singleLock.UnLock();


4、事件对象(Event)
Event对象由CEvent类创建。一个Event对象可以有两种状态:有信号状态和无信号状态。线程通过检测Event对象的状态进行相应的处理。
(1)创建:CEvent StartThread;
(2)创建完之后,Event对象自动处于无信号状态,要给Event对象发送信号:StartThread.SetEvent();
(3)线程通过以下函数来检测事件的信号:
::waitForSingleObject(StartThread.m_hObject,INFINITE);
此函数的两个参数分别是要检测的Event对象的句柄(在该Event对象的m_hObject成员变量中)和等待该信号准备花的时间,INFINITE表示无时间限制即无限期的等待。 


你可能感兴趣的:(Windows同步对象)