Win32多线程开发(Critical,Event,Mutex,Semphore)

来源:互联网 发布:毒舌电影 网络大电影 编辑:程序博客网 时间:2024/05/17 06:05

  一.   Mutex


 相关的API:

HANDLE CreateMutex(PSECURITY_ATTRIBUTES psa, BOOL fInitialOwner, PCTSTR pszName);

HANDLE OpenMutex(DWORD fdwAccess, BOOL bInheritHandle, PCTSTR pszName);

HANDLE ReleaseMutex(HANDLE hMUtext);


简单说明:Mutex对象在内核中是一个结构体,包括:使用计数,线程ID,递归计数器。当线程ID为0时,表示当前是有信号的

1. HANDLE CreateMutex(PSECURITY_ATTRIBUTES psa, BOOL fInitialOwner, PCTSTR pszName);


参数psa:用来设定Mutex对象的安全描述符和是否允许子进程继承句柄,通常PSECURITY_ATTRIBUTES结构表示该对象是内核对象;

参数fInitialOwner:用来控制Mutex的初始状态,如果为TRUE,表示当前线程持有该Mutex对象,将该Mutex对象的线程ID设置为当前线程的ID,递归计数器加一,由于线程ID不为0,此时Mutex对象是无信号的。如果fInitialOwner为FALSE,那么系统将Mutex对象的线程ID和递归计数器设置为0,此时该Mutex对象不被任何线程拥有,是有信号的。

参数pszName:用来设置Mutex的名字,该名字的格式是可以区别大小写的,但不能包含“/”,最大长度是MAX_PATH,为了较好的避免操作系统中其他进程也用到该名字,可以用GUID来表示,或者是company+GUID的格式,当然,也可以设置为NULL,表明该Mutex是匿名对象。

返回值:如果调用成功,返回Mutex的句柄,该句柄是用来控制内核模式下的互斥对象,否则返回NULL。注意:如果该Mutex是由名字的,当调用成功后,调用GetLastError()的返回值如果是ERROR_ALREADY_EXISTS,表示该Mutex对象已经存在,此时忽略fInitilOwner的值。


 二.   基本概念


互斥量(Mutex)是一种内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥量包含一个使用计数,一个线程ID和一个递归计数器。互斥量的行为特性与临界区相同,但Mutex是内核对象,临界区是用户模式对象,即Mutex的运行速度要比临界区慢,但是也意味着不同进程中的多个线程能够访问单个Mutex对象,并且等待访问资源的线程可以设定一个超时值。


互斥量中的线程ID用来标识系统当前哪个线程拥有互斥对象,如果为0表示没有线程拥有该Mutex,是有信号的,而决定ID为0的是递归计数器,递归计数器表示该线程目前拥有互斥对象的次数,即wait互斥对象成功的次数,假设当前线程初始化时拥有该Mutex,然后在wait一次,这时递归计数器为2,表示目前线程拥有该互斥对象的2次,需要调用ReleaseMutex()两次后,才能将递归计数器置为0,一旦递归计数器置为0,系统就将该Mutex的线程ID置为0,此时该Mutex是由信号的,不被任何线程拥有。这里一次要注意的地方就是ReleaseMutex()的调用次数。使用计数,即该Mutex在用户模式下的句柄个数,比如说,在调用CreateMutex()的时候,产生了一个Mutex句柄,然后再调用OpenMutex()一次,此时该Mutex对象的使用计数为2,调用CloseHandle()一次可以让Mutex的使用计数减少一次,当所有的Mutex句柄都Close后,使用计数就为0,此时系统将会销毁这个Mutex的内核对象。


互斥对象不同于其他内核对象,它有个线程所有权的问题,即某线程拥有了该Mutex对象后,只能在该线程中Release,因为加锁的时候记录了拥有该资源的线程的id,如果在另一个线程中解锁,这个线程目前根本不拥有该资源,解锁肯定失败。即如果调用ReleaseMutex()的线程并没有获得互斥量,即该线程的ID不等于互斥量的线程ID,那么ReleaseMutex()函数将不做任何操作,将FALSE返回给调用线程,调用GetLastError(),将返回ERROT_NOT_OWNER;另一种情况是,如果在释放互斥量子花钱,拥有互斥量的线程已经终止运行,那么系统将自动把互斥量中的线程ID和递归计数置为0,使Mutex对象是有信号的。