在多线程编程中,互斥体是一种重要的临界区保护机制,能够确保同一时间只有一个线程可以访问受保护的共享资源。在Windows下,CreateMutex函数是创建互斥体的一种常见方法。然而,虽然CreateMutex看上去很简单,但是错误的使用却可能导致程序崩溃或者产生不可预测的结果。本文将介绍如何正确地使用CreateMutex函数创建互斥体。
1. 什么是互斥体?
在多线程编程中,互斥体是用来保护临界区的一种机制。临界区是指一段代码,在同一时间只能由一个线程进行访问。在互斥体的保护下,同一时间只有一个线程可以进入临界区,其它线程必须等待互斥体的释放才能进入。因此,互斥体可以防止多个线程同时访问同一个共享资源,从而避免数据竞争和产生不可预测的结果。
在Windows下,互斥体被实现为一个同步对象,其类型为互斥体对象(Mutex Object)。创建互斥体的方法有多种,其中CreateMutex函数是一种常见的方法。
2. CreateMutex函数的定义和用法
CreateMutex函数的定义如下:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 互斥体的安全属性,一般为NULL
BOOL bInitialOwner, // 初次创建互斥体时,是否将其设为有所属者
LPCTSTR lpName // 互斥体的名字,可以为NULL
);
CreateMutex函数的参数非常简单,它有三个参数,分别是:
(1)LPSECURITY_ATTRIBUTES lpMutexAttributes:互斥体的安全属性。
(2)BOOL bInitialOwner:创建互斥体时,是否将其设为有所属者。
(3)LPCTSTR lpName:互斥体的名字。
CreateMutex函数返回一个互斥体的句柄,这个句柄可以被用作之后对互斥体的操作。
3. CreateMutex的使用原则
在使用CreateMutex函数创建互斥体时,需要注意以下几点:
(1)在同一个进程内,不要创建多个名称相同的互斥体。如果多次创建同一个名称的互斥体,那么每次创建互斥体时,都应该使用OpenMutex函数打开已经存在的互斥体。
(2)在初次创建互斥体时,建议采用默认值,即lpMutexAttributes为NULL,bInitialOwner为FALSE,lpName为NULL。
(3)在获得互斥体的句柄之后,应该在使用完之后正确地关闭互斥体句柄,即使用CloseHandle函数。(如果互斥体句柄没有关闭,可能会导致系统资源的浪费和进程崩溃)
4. CreateMutex的使用案例
下面通过一个示例程序来演示如何使用CreateMutex函数创建互斥体。这个示例程序会创建一个互斥体,然后启动两个线程,这两个线程会轮流地进入临界区,实现了对共享资源的互斥访问。
#include
#include
using namespace std;
#define THREAD_COUNT 2
#define LOOP_COUNT 5
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
HANDLE hMutex = (HANDLE)lpParameter;
for (int i = 0; i < LOOP_COUNT; i++)
{
WaitForSingleObject(hMutex, INFINITE);
cout << "Thread " << GetCurrentThreadId() << " enters critical section." << endl;
Sleep(1000);
cout << "Thread " << GetCurrentThreadId() << " leaves critical section." << endl;
ReleaseMutex(hMutex);
}
return 0;
}
int main()
{
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
HANDLE hThread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadProc, hMutex, 0, NULL);
if (hThread[i] == NULL)
{
cout << "Thread " << i + 1 << " creation failed." << endl;
}
}
WaitForMultipleObjects(THREAD_COUNT, hThread, TRUE, INFINITE);
CloseHandle(hMutex);
for (int i = 0; i < THREAD_COUNT; i++)
{
CloseHandle(hThread[i]);
}
return 0;
}
在这个示例程序中,我们首先创建了一个互斥体句柄hMutex,然后创建了两个线程。这两个线程都会调用ThreadProc函数。ThreadProc函数的第一个参数是hMutex,即这个线程需要使用的互斥体句柄。
在ThreadProc函数中,每个线程都会调用WaitForSingleObject函数等待互斥体。如果互斥体当前没有被任何线程使用,则线程获得该互斥体,进入临界区,并输出一条消息。在临界区中,线程调用Sleep函数停留1秒钟,然后离开临界区,释放互斥体,并输出一条消息。
5. 总结
互斥体是多线程编程中的一种重要机制,能够保护临界区,避免数据竞争和产生不可预测的结果。在Windows下,CreateMutex函数是一种创建互斥体的常见方法。正确地使用CreateMutex函数可以保证程序的正确性和稳定性。当然,除了CreateMutex函数,Windows下还有很多其他的函数可以实现互斥体的创建或使用,你可以根据具体的需求选择最合适的函数。