利用互斥对象实现线程同步
1) 互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。
2) 互斥对象包含一个使用数量,一个线程ID和一个计数器。
3) ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。
使用CreateMutex来创建互斥对象,用ReleaseMutex来释放互斥对象
在线程执行程序中用WaitForSingleObjec来获得互斥对象,使用完要用ReleaseMutex来释放互斥对象
三种实现同步方法即使用互斥对象、事件对象与关键代码段的比较
1) 互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。
2) 关键代码段是工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值。
下面为使用关键代码段来模拟简单多线程售卖火车票的例子:
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Func1Proc(
LPVOID lpParameter // thread data
);
DWORD WINAPI Func2Proc(
LPVOID lpParameter // thread data
);
int index=100;
int tickets=100;
HANDLE hmutex;
main()
{
HANDLE hthread1;
HANDLE hthread2;
DWORD threadid1;
DWORD threadid2;
hthread1=CreateThread(NULL,0,Func1Proc,NULL,0,&threadid1);
hthread2=CreateThread(NULL,0,Func2Proc,NULL,0,&threadid2);
CloseHandle(hthread1);
CloseHandle(hthread2);
hmutex=CreateMutex(NULL,FALSE,"tickets");
if(hmutex)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only instance can run!"<<endl;
return 1;
}
}
ReleaseMutex(hmutex);
Sleep(4000);
return 0;
}
DWORD WINAPI Func1Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(hmutex,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sells ticket"<<tickets--<<endl;
}
else
break;
ReleaseMutex(hmutex);
}
return 0;
}
DWORD WINAPI Func2Proc(LPVOID lpParameter)
{
while(TRUE)
{
WaitForSingleObject(hmutex,INFINITE);
if(tickets>0)
{
Sleep(1);
cout<<"thread2 sells ticket"<<tickets--<<endl;
}
else
break;
ReleaseMutex(hmutex);
}
return 0;
}