线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应该一直等待,直到消息到达时才被唤醒.
线程互斥是指对于共享资源,在各线程访问时的排它性。即当有多个线程都要使用某一共享资源时,同一时刻却只允许一个线程去使用,而其他要使用的该共享资源的线程必须等待,直到占用资源者释放该共享资源。
实际上线程互斥是一种特殊的线程同步。
在Win32中,同步机制主要有以下几种:
一、全局变量
int var ; //全局变量
UINT ThreadFunction(LPVOID pParam)
{
while(var)
{
//线程处理
}
return 0 ;
}
二、事件
1.创建事件
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL bManualReset,
BOOL bInitialState,
PCTSTR pszName);
- 第一个参数与CreateThread中的第一个参数类似,是一个指向SECURITY_ATTRIBUTES结构的指针;
第二个参数bManualReset告诉系统创建manual-reset(TRUE)还是auto-reset(FALSE)类型的对象;(当manual-reset事件状态变为signaled时,所有等待该事件的线程都成为可调度的,当auto-reset事件状态变为signaled时,等待该事件的所有线程中只会有一个成为可调度的。)
第三个参数bInitialState用来指明事件对象的状态初始化为signaled(TRUE)或unsignaled(FALSE);
第四个参数为事件的名称。
2.打开和关闭事件
HANDLE hEvent = OpentEvent(EVETN_ALL_ACCESS, true, “MyEvent”) ;
CloseHandle(hEvent) ;
3.状态控制
函数SetEvent将事件对象置为signaled状态:
BOOL SetEvent(HANDLE hEvent)
函数ResetEvent将事件对象重置为unsignaled:
BOOL ResetEvent(HANDLE hEvent) - 微软为auto-reset类型的事件对象定义了“成功等待的副作用”——当某线程等待该对象成功时,对象状态会自动重置为unsignaled,因此通常没有必要为auto-reset类型的对象调用ResetEvent。要注意,微软并未为manual-reset类型的事件对象定义这种机制。
4.等待控制
WaitForSingleObject(evRead, INFINITE) ;
5.实例
…
三、临界区
临界区适用于多个线程之间没有先后顺序但要求互斥的同步。多个线程访问同一个临界区的原则:
(1)一次最多只能一个线程停留在临界区内;
(2)不能让一个线程无限地停留在临界区内,否则其他线程将不能进入临界区。
定义临界区变量的方法如下:
CRITICAL_SECTION gCriticalsection ;
初始化临界区:
VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) ;
删除临界区:
VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) ;
进入临界区:
VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) ;
离开临界区:
VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) ;
四、互斥量
CreateMutex:创建一个互斥对象,返回对象句柄;
OpenMutex:打开并返回一个已经存在的互斥对象的句柄,使之后续访问;
WaitForSingleObject(hMutex, INFINITE) :等待互斥量;
ReleaseMutex:释放互斥对象占用,使之成为可用。
五、信号量
信号量是一个核心对象,拥有一个计数器,可以用来管理大量有限的系统资源。当计数器大于零时,信号量为有信号状态;当计数器为零时,信号量处于无信号状态。
创建信号量:
HANDLE CreateSemaphore( PSECURITY_ATTRIBUTE psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR psaName) ;
释放信号量:
BOOL WINAPI ReleaseSemaphoe(HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount) ;
打开信号量:
HANDLE OpenSemaphore( DWORD fdwAccess,
BOOL bInherithandle,
PCTSTR pszName) ;
六、模板
#include <windows.h>
#include <iostream.h>
#define THREAD_INSTANCE_NUMBER 3
LONG g_fResourceInUse = FALSE ;
LONG g_lCounter = 0 ;
DWORD ThreadProc(void *pData)
{
int ThreadNumberTemp = (*(int*)pData) ;
HANDLE hMutex ;
//1.打开互斥量
if((hMutex=OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex.Test"))==NULL)
{
cout<<"Open Mutex error!"<<endl ;
return 1 ;
}
//2.等待互斥
WaitForSingleObject(hMutex, INFINITE) ;
//3.用户代码**********
//4.释放互斥量
ReleaseMutex(hMutex) ;
//5.关闭句柄
CloseHandle(hMutex) ;
return 0 ;
}
int main(int argc, char *argv[])
{
int i;
DWORD ID[THREAD_INSTANCE_NUMBER];
HANDLE h[THREAD_INSTANCE_NUMBER];
HANDLE hMutex ;
//创建互斥量
if((hMutex=OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex.Test"))==NULL)
if((hMutex=CreateMutex(NULL,FALSE, "Mutex.Test"))==NULL)
{
cout<<"Create Mutex error!"<<endl ;
return 0 ;
}
for(i=0; i<THREAD_INSTANCE_NUMBER ;i++)
{
h[i] = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE) ThreadProc,
(void *) &ID[i],
0,
&(ID[i])) ;
if(h[i]==NULL)
cout<<"CreateThread error"<<ID[i]<<endl ;
else
cout<<"CreateThread :"<<ID[i]<<endl ;
}
WaitForMultipleObjects(THREAD_INSTANCE_NUMBER, h, TRUE, INFINITE) ;
cout<<"Close the Mutex Handle!"<<endl;
CloseHandle(hMutex) ;
return 0 ;
}