CreateMutex是Windows操作系统中的一个函数,它可以创建一个同步对象。在计算机编程中,同步是指在多个线程或进程中控制并发访问共享资源的机制,可以避免一些竞态条件和死锁问题。CreateMutex函数可以用于创建互斥锁(Mutex)、指针信号量(Semaphore)和自旋锁(Spinlock)等同步机制。
下面就来介绍一下如何使用CreateMutex函数创建同步对象。
一、创建Mutex对象
Mutex(互斥锁)是最简单也是最常用的同步对象之一。Mutex可以防止多个线程同时访问共享资源,从而保证资源的正确性。当一个线程请求Mutex时,如果此Mutex已经被另一个线程占用,那么请求的线程将会被挂起,直到Mutex被释放。
使用CreateMutex函数可以创建一个Mutex对象。函数原型如下:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
其中,lpMutexAttributes参数指定了Mutex对象的安全属性,如果为NULL,那么Mutex对象的安全属性默认为可继承的;bInitialOwner参数指定了创建Mutex对象时是否占用此Mutex,如果为TRUE,则创建Mutex对象时该线程自动拥有该Mutex,否则Mutex对象的状态为未占用状态;lpName参数指定了Mutex对象的名称,该参数为可选参数,可以为NULL。
下面是一个简单的使用CreateMutex函数创建Mutex对象的示例代码:
HANDLE hMutex = CreateMutex(NULL, FALSE, _T("MyMutex"));
如果hMutex返回值为NULL,说明创建Mutex对象失败。我们可以通过调用GetLastError函数来获取错误码,然后根据错误码调用FormatMessage函数获取错误信息。
二、使用Mutex对象同步
创建Mutex对象之后,我们可以使用WaitForSingleObject或WaitForMultipleObjects等函数来等待Mutex对象被释放。调用WaitForSingleObject函数可以等待一个Mutex对象被占用或者等待一段时间以后返回。函数原型如下:
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
其中,hHandle参数指定了要等待的对象句柄,此处是Mutex对象的句柄;dwMilliseconds参数指定了等待的时间,如果为INFINITE,则表示无限等待直到Mutex对象被释放。
下面是一个简单的使用Mutex对象同步的示例代码:
DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
if(dwWaitResult == WAIT_OBJECT_0) //Mutex被占用
{
//处理Mutex被占用的情况
ReleaseMutex(hMutex); //释放Mutex
}
else if(dwWaitResult == WAIT_TIMEOUT) //等待超时
{
//处理等待超时的情况
}
else //等待失败
{
//处理等待失败的情况
}
上述代码中,调用WaitForSingleObject函数会阻塞线程,直到Mutex对象被释放。如果Mutex被占用,函数返回WAIT_OBJECT_0;如果等待超时,函数返回WAIT_TIMEOUT;如果等待失败,函数返回WAIT_FAILED。
当Mutex对象被释放时,我们可以调用ReleaseMutex函数来释放Mutex。函数原型如下:
BOOL ReleaseMutex(
HANDLE hMutex
);
三、创建Semaphore对象
Semaphore(信号量)是另一种常用的同步对象,Semaphore可以允许多个线程同时访问共享资源,从而提高并发性能。Semaphore还可以用来控制进程之间的并发访问。
使用CreateSemaphore函数可以创建一个Semaphore对象。函数原型如下:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
);
其中,lpSemaphoreAttributes参数指定了Semaphore对象的安全属性,如果为NULL,那么Semaphore对象的安全属性默认为可继承的;lInitialCount参数指定了Semaphore对象的初始计数值,通常为0或1;lMaximumCount参数指定了Semaphore对象的最大计数值,最大计数值应该大于等于初始计数值,通常为1或无限大;lpName参数指定了Semaphore对象的名称,该参数为可选参数,可以为NULL。
下面是一个简单的使用CreateSemaphore函数创建Semaphore对象的示例代码:
HANDLE hSemaphore = CreateSemaphore(NULL, 1, 1, _T("MySemaphore"));
如果hSemaphore返回值为NULL,说明创建Semaphore对象失败。我们可以通过调用GetLastError函数来获取错误码,然后根据错误码调用FormatMessage函数获取错误信息。
四、使用Semaphore对象同步
创建Semaphore对象之后,我们可以使用WaitForSingleObject或WaitForMultipleObjects等函数来等待Semaphore对象,也可以使用ReleaseSemaphore函数来释放Semaphore对象。
调用WaitForSingleObject函数等待Semaphore对象时,如果Semaphore对象的计数值为0,那么线程将会被挂起,直到Semaphore对象的计数值大于0。如果Semaphore对象的计数值大于等于1,那么线程将会立即返回。函数原型如下:
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
其中,hHandle参数指定了要等待的对象句柄,此处是Semaphore对象的句柄;dwMilliseconds参数指定了等待的时间,如果为INFINITE,则表示无限等待直到Semaphore对象的计数值大于0。
下面是一个简单的使用Semaphore对象同步的示例代码:
DWORD dwWaitResult = WaitForSingleObject(hSemaphore, INFINITE);
if(dwWaitResult == WAIT_OBJECT_0) //Semaphore计数值大于0
{
//访问共享资源
ReleaseSemaphore(hSemaphore, 1, NULL); //将Semaphore计数值减1
}
else if(dwWaitResult == WAIT_TIMEOUT) //等待超时
{
//处理等待超时的情况
}
else //等待失败
{
//处理等待失败的情况
}
上述代码中,调用WaitForSingleObject函数会阻塞线程,直到Semaphore对象的计数值大于0。如果Semaphore计数值大于等于1,函数返回WAIT_OBJECT_0;如果等待超时,函数返回WAIT_TIMEOUT;如果等待失败,函数返回WAIT_FAILED。
当线程结束访问共享资源时,我们可以调用ReleaseSemaphore函数将Semaphore计数值减1,以便其他线程可以访问共享资源。
五、总结
使用CreateMutex和CreateSemaphore函数可以创建Mutex和Semaphore同步对象,利用这些同步对象可以控制并发访问共享资源的行为。在使用同步对象时应该遵循以下原则:
1. 同步对象应该在共享资源的访问前创建,且必须由所有访问共享资源的线程共享。
2. 对于Mutex对象,应该在读写共享资源之前使用WaitForSingleObject函数获取Mutex,读写共享资源之后使用ReleaseMutex函数释放Mutex,以保证只有一个线程访问共享资源。
3. 对于Semaphore对象,应该在读写共享资源之前使用WaitForSingleObject函数获取Semaphore,读写共享资源之后使用ReleaseSemaphore函数将Semaphore计数值减1,以便其他线程可以访问共享资源。
4. 在使用WaitForSingleObject等等待函数时,应该注意避免死锁或者饥饿问题。如果线程调用WaitForSingleObject函数等待同步对象的信号时被钦定了优先级,那么线程也可能会出现饥饿现象。