互斥量(mutex)是一种内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥量包含一个使用数量,一个线程 ID 和一个递归计数器。ID用于标识系统中的哪个线程当前拥有互斥对象,递归计数器用于指明该线程拥有互斥对象的次数。互斥量的行为特性与临界段相同,但是互斥量属于内核对象,而临界段属于用户方式对象。这意味着互斥量的运行速度比临要慢,但是这也意味着不同进程中的多个线程能够访问单个互斥量,并且这意味着对等待访问资源的线程可以设定一个超时值。
互斥对象有许多用途,属于最常用的内核对象之一。通常来说,它们用于保护由多个线程访问的内存块。如果多个线程要同时访问内存块,内存块中的数据就可能遭到破坏。互斥对象能够保证访问内存块的任何线程拥有对该内存块的独占访问权,这样就能够保证数据的完整性。
要使用互斥量,必须先调用CreateMutex创建此互斥量
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
其中:
lpMutexAttributes参数指向一个SECURITY_ATTRIBUTES结构,这个结构在98中将被忽略,在NT/2K中它指定一个安全描述,如果忽略这个,Mutex将得到一个缺省的安全描述。
bInitialOwner参数如果为True表示此线程将拥有此互斥量,因此互斥量将处于无信号状态。任何在此互斥量上等待的线程都将被挂起,直到创建此互斥量的线程释放它。如果此参数为FALSE,就表示此互斥量不被任何线程拥有,因而创建后处于有信号状态。第一个等待此互斥量的线程将立刻获得此互斥量的所有权并继续运行。
lpName参数要么是NULL,要么是一个标志互斥量的以0为结束符的字符串做为名字。
在调用CreateMutex后要立即调用GetLasrError,如果返回值为ERROR_ALREADY_EXISTS,就表明没有创建新的互斥量对象。
当目前拥有对资源的访问权的线程不再需要它的访问权时,它必须调用ReleaseMutex函数来释放该互斥对象
BOOL ReleaseMutex(HANDLE hMutex);
和临界区一样,互斥量有着与之相联系的所有权计数,如果某线程拥有了互斥量再次调用WaitForSingleObject时,该互斥量的引用计数将增加,所以必须调用相同次数的ReleaseMutex来释放此互斥量。
当互斥量使用完后调用CloseHandle关闭互斥量。
互斥量同步进程
要使用互斥量来同步进程,两个进程中的某个进程必须拥有同一互斥量对象的进程相关句柄。可以通过两种方法获得此句柄。一是在第二个线程创建互斥量时使用与第一个互斥量一样的lpName,此时就不再创建新的互斥量而是返回标识已有互斥量的进程相关句柄。另一种获得的方法是使用
HANDLE OpenMutex(
DWORD dwDesiredAccess, // MUTEX_ALL_ACCESS或SYNCHRONIZE(NT Only)
BOOL bInheritHandle, // 指明此进程创建的任一子进程是否应该继承此互斥量。
LPCTSTR lpName // 互斥量的名字
);
调用OpenMutex时,系统将扫描所有现存的互斥量,如果找到lpName指定的互斥量。就返回给调用线程,如果找不到就返回NULL。