一、线程的同步
创建互斥对象完成线程同步 :
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName );
打开一个命名的或者没有名字的互斥对象:
参数1:指向SECURITY_ATTRIBUTES结构体的指针。可以传递NULL,让其使用默认的安全性。
参数2:指示互斥对象的初始拥有者。如果该值是真,调用者创建互斥对象,调用的线程获得互斥对象
的所有权。否则,调用线程捕获的互斥对象的所有权。(就是说,如果该参数为真,则调用
该函数的线程拥有互斥对象的所有权。否则,不拥有所有权)
参数3:互斥对象名称。传递NULL创建的就是没有名字的互斥对象,即匿名的互斥对象。
返回值:如果函数成功,返回Mutex对象的一个句柄。如果命名的互斥对象在调用函数前已经存在,
函数返回已经存在的互斥对象的句柄,然后调用GetLastError返回ERROR_ALREADY_EXISTS。
否则,调用者创建互斥对象。
例://创建匿名互斥对象
//当前没有线程拥有互斥对象,操作系统会将互斥对象设置为已通知状态(有信号状态)
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
另:关于互斥对象
*互斥对象(Mutex)属于内核对象,它能确保线程拥有对单个资源的互斥访问权。
*互斥对象包含一个使用数量,一个线程ID(哪个线程拥有互斥对象,就设置为哪个线程的线程ID)和一个计数器。
*ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。
二、在线程中请求互斥对象
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
出现下面情况之一时返回:
1、指定的对象处于有信号状态;
2、超出了超时(time-out)的时间间隔。
参数1:对象的句柄,这里传递的是互斥对象的句柄。一旦互斥对象变成有信号状态,该函数返回。
如果互斥对象始终没有处于有信号状态(非信号状态),函数将一直处于等待,导致线程
暂停运行。
参数2:指定超时的时间间隔,以毫秒为单位。
如果时间间隔流逝了,函数就返回,即使等待的互斥对象处于非信号状态;
如果将该参数设置为0,该函数测试对象的状态然后立即返回;
如果将该参数设置为INFINITE,函数的超时值永远不会发生,也就是说函数将永远等待,直到
所等待的对象处于有信号状态。
注意:可以在我们需要保护的代码前面加上WaitForSingleObject(),当我们请求互斥对象的时候
操作系统会判断请求互斥对象的线程和拥有互斥对象的线程的ID是否相等,如果相等,即使
互斥对象处于未通知状态(非信号状态),仍然能够获得互斥对象的所有权。操作系统通过
互斥对象的计数器记录请求了多少次互斥对象。
另:可通过该函数的返回值,得知如何获得的互斥对象所有权。
例://除非等待的互斥对象变为有信号状态,才继续运行,否则永远等待
WaitForSingleObject(hMutex, INFINITE);
//如果互斥对象处于有信号状态(已通知状态)则得到互斥对象,并将互斥对象设置为
//未通知状态(非信号状态),然后继续运行。
三、释放互斥对象
释放互斥对象,使互斥对象处于已通知状态(有信号状态):
BOOL ReleaseMutex( HANDLE hMutex );释放指定互斥对象的所有权。如果成功返回非0值,失败返回0。在需要保护的代码后调用ReleaseMutex释放互斥对象,操作系统会将互斥对象的线程ID设置为0,并将互斥对象设置为已通知状态(有信号状态)。同时,互斥对象的计数器减一。注意:调用该函数的时候,操作系统会判断调用线程ID与互斥对象内部所维护的线程ID号是否相等,如果不等,互斥对象就不能被释放。释放互斥对象的原则:谁拥有,谁释放。四、调用的形式//在主线程中...HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);...//其他线程中...WaitForSingleObject(hMutex, INFINITE);//受保护的代码...ReleaseMutex(hMutex);
五、互斥对象的一个应用
//避免同一程序运行多次
hMutex = CreateMutex(NULL, FALSE, "mutex");
if (hMutex)
{
if ( ERROR_ALREADY_EXISTS == GetLastError() )
{
cout<<"仅可以运行一个实例!"<<endl;
return;
}
}