关于Win32同步锁

CSyncObject : 这个类是为win32提供公共同步接口的只有纯虚函数基类。

微软基础类库提供了一些继承自CSyncObject的类。那就是CEvent,CMutex,CCriticalSection,和CSemaphore。
CSyncObject
|
|--CCriticalSection (临界区)
|--CMutex (互斥量)
|--CSemaphore (信号量)
|--CEvent (事件)

MFC 提供的多线程类分为两类:
1、同步对象(CSemaphore、CMutex、CCriticalSection 和 CEvent);
2、同步访问对象(CMultiLock 和 CSingleLock)。

Critical Section(临界区)用来实现“使用资源排他性占有”,即:“资源”每一次(同一时间内)只能够被一个线程处理。
特点:
    1、局部性对象,非核心对象,存在于进程的内存空间中;
2、效率速度高,非宜长期占用,1次1个占用。
3、只能在同一进程中使用。
缺点:
    1、没有办法获知进入critical section中的那个线程是生是死:
  从另一个角度看,由于critical section不是核心对象,如果进入critical section的那个线程结束了或当掉了,而没有调用LeaveCriticalSection()的话,系统没有办法将该critical section清除的,这样导致死锁了。
2、不能指定等待时间;
3、
注意:
    最牢靠而最立即的警告:千万不要在一个critical section之中调用Sleep()或任何Wait...() API函数。

Mutex(互斥量)一个时间内只能够有一个线程拥有(1次1个占用)
特点:
    1、核心对象;
2、mutex可以跨进程使用;
3、可以使用Wait...()等待mutex,而且可以指定等待时间;
4、可以命名,并且根据这个名字可以被其他线程处理;
5、假如拥有mutex的那个线程结束前未调用ReleaseMutex(),mutex不会被摧毁,取而代之的是该mutex会被视为“未被拥有”以及 “未被激发”,而下一个等待中的线程会被以WAIT_ABANDONED_0通知,不论线程是因为ExitThread()而结束的,或是因当掉而结束
  的,这种情况都存在;
6、只能被拥有它的那个线程释放。
缺点:
    1、牺牲速度以增加弹性;
  锁住一个未被拥有的mutex需要的时间是锁住一个未被拥有的critical section的几乎100倍的时间,因为critical section不需要进入操作系统核心,而直接在“user mode”就可以进行操作。
2、mutex是用来确保某些操作能够自动被进行的,如果线程死于半途,很有可能被保护的那些数据会受到无法修复的伤害。
    
Semaphore(信号量)解决各种producer/consumer问题的关键要素,这种问题会存有一个缓冲区,可能在同一时间内被读出数据或被写入数据。(可以多个同时使用)
特点:
    1、核心对象;
2,无拥有者;
3,可以命名,根据这个名字可以被其他进程开启使用;
4,可以被任何1个线程释放。
缺点:
    1、由于需要有用户模式切换到内核模式,效率较低;
2、必须要有公共内存,不能用于分布式系统;
3、忙等待,浪费CPU的时间(要知道,以前使用计算机是按CPU时间收费的),这种类型的信号量也称自旋锁(spinlock)。
    
Event Objects(事件)通常就为用于overlapped I/O,或用来设计构造某些自定义设置的同步对象。
特点:
    1、核心对象;
2、完全在程序代码的掌控之下;
3、适用于设计构造新的同步对象;
4,可以命名,可以根据名字被其他进程开启。
缺点:
    1、当没有任何线程正在等待时,“要求苏醒”的event并非会被存贮起来,可能会遗失掉。换句话说,除非有线程正在等待,否则event不会被保存下来。
2、另一种情况可能会引起死锁,假设“receiver”线程检查队列中是否有字符,这时候发生context switch,切换到“sender”线程,他对一个event对象进行pulse操作,这时候又发生context switch,回到receiver线程,调用WaitForSingleObject()等待event对象,由于这个动作发生在sender线程激发event之后,所以event会遗失,于是receiver永远不会醒来,程序进入死锁状态,这正是semaphore之所以被创造用以解决为题的地方。


当必须控制对资源的访问以确保资源的完整性时,使用同步类。而同步访问类用于获取对这些资源的访问权。

1. 何时使用同步类
    若要确定应使用的同步类,请询问以下一系列问题:
    1)应用程序必须等到发生某事才能访问资源(例如,在将数据写入文件之前,必须先从通信端口接收它)吗?
  如果是,请使用 CEvent。
    2)同一应用程序内一个以上的线程可以同时访问此资源(例如,应用程序允许在同一文档上最多同时打开五个带有视图的窗口)吗?
  如果是,请使用 CSemaphore。
    3)可以有一个以上的应用程序使用此资源(例如,资源在 DLL 中)吗?
  如果是,请使用 CMutex。
  如果不是,请使用 CCriticalSection。
从不直接使用 CSyncObject。它是其他四个同步类的基类。

2. 何时使用同步访问类
   如果应用程序只与访问单个受控资源有关,请使用 CSingleLock。
   如果需要访问多个受控资源中的任何一个,则使用 CMultiLock。
   
3. 如何使用同步类
   写入多线程应用程序时,线程间的同步资源访问是一个常见问题。两个或多个线程同时访问同一数据会导致不合需要的、不可预知的结果。例如,一个线程可能正在更新结构的内容,而另一个线程正在读取同一结构的内容。无法得知读取线程将会收到何种数据:旧数据、新写入的数据或两种数据都有。MFC 提供了多个同步类和同步访问类以帮助解决此问题。
    典型的多线程应用程序具有代表各个线程间要共享的资源的类。正确设计的完全线程安全类不需要调用任何同步函数。该类的任何事情都在内部处理,使您可以将精力集中于如何更好地使用类,而不是它如何会损坏。创建完全线程安全类的有效技术是将同步类合并到资源类中。将同步类合并到共享类是一个简单的过程。
    以维护链接的帐户列表的应用程序为例。此应用程序允许在独立的窗口中最多检查三个帐户,但是在任何特定的时间,只能更新一个帐户。更新帐户后,通过网络将更新的数据发送到数据存档。
    此示例应用程序使用所有这三种类型的同步类。因为它一次最多允许检查三个帐户,所以它使用 CSemaphore 限制对三个视图对象的访问。当试图查看第四个帐户时,应用程序或者等到前三个窗口中有一个关闭,或者该尝试失败。更新帐户时,应用程序使用 CCriticalSection 确保一次只更新一个帐户。更新成功后,发出信号 CEvent 以释放等待该事件信号发送的线程。此线程将新数据发送到数据存档。


参考:
http://blog.csdn.net/wcyoot/article/details/7369628
Win32多线程程序设计

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值