http://www.programfan.com/blog/article.asp?id=23757
1、利用事件对象实现多线程的同步:
#include<windows.h>
#include<iostream.h>
DWORD WINAPI FunProc1(
LPVOID lpParameter // thread data
);
DWORD WINAPI FunProc2(
LPVOID lpParameter // thread data
);
int ticket=100;
HANDLE hEvent;
void main()
{
HANDLE hThread1,hThread2;
hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
hEvent=CreateEvent(NULL,false,false,"ticket");
/*该函数为创建事件对象
*第一个参数为NULL,表示使用缺省的安全性
*第二个参数当为true,必须用ResetEvent人工地将事件对象设置为无信号状态
当为false,在一个等待线程被释放后系统将事件对象自动设置为无信号状态
*第三个参数指定事件对象的初始状态,当为true为有信号状态,否则为无信号状态
*第四个参数为事件对象的命名,当为NULL该对象为匿名对象
*/
if(hEvent)
{
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
cout<<"the Event is exists!"<<endl;
return;
}
}
//该函数用于设置事件对象为有信号状态
SetEvent(hEvent);
Sleep(4000);
CloseHandle(hEvent);
}
DWORD WINAPI FunProc1(
LPVOID lpParameter // thread data
)
{
while(1)
{
WaitForSingleObject(hEvent,INFINITE);
//ResetEvent(hEvent);
if(ticket>0)
{
Sleep(1);
cout<<"thead1 is sell ticket:"<<ticket--<<endl;
}
else
break;
SetEvent(hEvent);
}
return 0;
}
DWORD WINAPI FunProc2(
LPVOID lpParameter // thread data
)
{
while(1)
{
WaitForSingleObject(hEvent,INFINITE);
//ResetEvent(hEvent);
if(ticket>0)
{
Sleep(1);
cout<<"thead2 is sell ticket:"<<ticket--<<endl;
}
else
break;
SetEvent(hEvent);
/*人工重置事件对象的做法存在两种问题:
*当线程1运行到WaitForSingleObject(hEvent,INFINITE)时间片用完,此时
*事件对象仍然处于有信号状态,线程2也进入到了受保护的语句。两个线程
*都进入了受保护的语句,不能实现线程的同步。
*当将这个程序移植到多CPU的机子上,两个线程同时进行,双方都进入了受
*保护的语句,不能实现线程的同步,人工重置已经不再起作用。
*/
}
return 0;
}
/*当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。
*当一个线程得到人工重置事件对象,该事件对象仍然处于信号状态。
*当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
*当一个线程得到自动重置事件对象,该事件对象仍然处于无信号状态。
*/
2、利用临界区实现多线程的同步:
#include<windows.h>
#include<iostream.h>
DWORD WINAPI FunProc1(
LPVOID lpParameter // thread data
);
DWORD WINAPI FunProc2(
LPVOID lpParameter // thread data
);
int ticket=100;
HANDLE hEvent;
void main()
{
HANDLE hThread1,hThread2;
hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
hEvent=CreateEvent(NULL,false,false,"ticket");
/*该函数为创建事件对象
*第一个参数为NULL,表示使用缺省的安全性
*第二个参数当为true,必须用ResetEvent人工地将事件对象设置为无信号状态
当为false,在一个等待线程被释放后系统将事件对象自动设置为无信号状态
*第三个参数指定事件对象的初始状态,当为true为有信号状态,否则为无信号状态
*第四个参数为事件对象的命名,当为NULL该对象为匿名对象
*/
if(hEvent)
{
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
cout<<"the Event is exists!"<<endl;
return;
}
}
//该函数用于设置事件对象为有信号状态
SetEvent(hEvent);
Sleep(4000);
CloseHandle(hEvent);
}
DWORD WINAPI FunProc1(
LPVOID lpParameter // thread data
)
{
while(1)
{
WaitForSingleObject(hEvent,INFINITE);
//ResetEvent(hEvent);
if(ticket>0)
{
Sleep(1);
cout<<"thead1 is sell ticket:"<<ticket--<<endl;
}
else
break;
SetEvent(hEvent);
}
return 0;
}
DWORD WINAPI FunProc2(
LPVOID lpParameter // thread data
)
{
while(1)
{
WaitForSingleObject(hEvent,INFINITE);
//ResetEvent(hEvent);
if(ticket>0)
{
Sleep(1);
cout<<"thead2 is sell ticket:"<<ticket--<<endl;
}
else
break;
SetEvent(hEvent);
/*人工重置事件对象的做法存在两种问题:
*当线程1运行到WaitForSingleObject(hEvent,INFINITE)时间片用完,此时
*事件对象仍然处于有信号状态,线程2也进入到了受保护的语句。两个线程
*都进入了受保护的语句,不能实现线程的同步。
*当将这个程序移植到多CPU的机子上,两个线程同时进行,双方都进入了受
*保护的语句,不能实现线程的同步,人工重置已经不再起作用。
*/
}
return 0;
}
/*当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。
*当一个线程得到人工重置事件对象,该事件对象仍然处于信号状态。
*当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
*当一个线程得到自动重置事件对象,该事件对象仍然处于无信号状态。
*/
3、利用互斥对象实现多线程的同步:
#include<windows.h>
#include<iostream.h>
DWORD WINAPI FunProc1(
LPVOID lpParameter // thread data
);
DWORD WINAPI FunProc2(
LPVOID lpParameter // thread data
);
int ticket=100;
HANDLE hMutex;
void main()
{
HANDLE hThread1,hThread2;
hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
/*第一个参数为NULL,表示使用缺省的安全性.
*第二个参数表示初始提交栈的大小,保留的地址空间大小是x86机子上页面大小的整数倍。
当小于缺省提交的大小,将使用调用线程的大小。
*第三个参数为线程运行函数的入口地址,主线程的入口函数为main.
*第四个参数为给线程传递参数。
*第五个参数为创建线程的控制标志.当为CREATE_SUSPENDED线程暂停,只有在调用
ResumeThread函数时才可继续执行. 当为零的时候创建的线程立即执行。
*第六个参数为接受线程的标识符。
Windows NT: If this parameter is NULL, the thread identifier is not returned.
Windows 95 and Windows 98: This parameter may not be NULL.
*/
CloseHandle(hThread1);
CloseHandle(hThread2);
//关闭线程句柄可以让线程内核对象的引用计数减1,当计数为零时则释放线程内核对象
hMutex=CreateMutex(NULL,true,"ticket");
/*该函数为创建一个有名字的或者匿名的互斥对象。
*第一个参数为NULL,表示使用缺省的安全性.
*第二个参数表示互斥对象初始的拥有者。当为true,该互斥对象被调用线程所拥有。false
反之。
*第三个参数为互斥对象的名字,如果为NULL则为匿名。
*/
if(hMutex)
{
//如果互斥对象已经创建
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
}
WaitForSingleObject(hMutex,INFINITE);
/*这个函数将使互斥对象的计数器继续加1,此时互斥对象的计数器变为2
*ReleaseMutex函数使互斥对象的计数器减1,此时互斥对象没有变为已通知状态
*/
ReleaseMutex(hMutex);
ReleaseMutex(hMutex);
//互斥对象只有谁拥有以后才能再释放
cout<<"main hThread is running!"<<endl;
//Sleep函数是在指定时间间隔中暂停当前的线程
Sleep(4000); /*主线程暂停,执行副线程*/
}
DWORD WINAPI FunProc1(
LPVOID lpParameter // thread data
)
{
/* while(1)
{
//ReleaseMutex(hMutex);这里释放互斥对象不成功,先前互斥对象的线程ID是主线程,不
是线程1
WaitForSingleObject(hMutex,INFINITE);
*该函数为等待互斥对象,当互斥对象处于有信号状态或者在时间间隔中流逝函数返
回
*第一个参数为等待对象的句柄
*第二个参数当为INFINITE,函数永远等待下去不会返回WAIT_TIMEOUT
*当为零时函数检测后立即返回。
*
if(ticket>0)
{
Sleep(1);//人为的交换,线程1与线程2交替进行,也会出现问题
cout<<"thead1 is sell ticket:"<<ticket--<<endl;
}
else
break;
ReleaseMutex(hMutex);
//释放互斥对象的所有权
}
*/
WaitForSingleObject(hMutex,INFINITE);
cout<<"thread1 is running!"<<endl;
/*当进程结束后,系统会自动将互斥对象的ID设为空,计数器设为零
*因此不调用ReleaseMutex函数互斥对象也会被释放。
*/
return 0;
}
DWORD WINAPI FunProc2(
LPVOID lpParameter // thread data
)
{
/* while(1)
{
WaitForSingleObject(hMutex,INFINITE);
if(ticket>0)
{
Sleep(1);
cout<<"thead2 is sell ticket:"<<ticket--<<endl;
}
else
break;
ReleaseMutex(hMutex);
}
*/
WaitForSingleObject(hMutex,INFINITE);
cout<<"thread1 is running!"<<endl;
return 0;
}