利用事件对象实现线程同步

        事件对象也属于内核对象,允许任意数目的线程对资源拥有同步访问的权限,该对象包含:使用计数、指示人工重置事件/自动重置事件的布尔值、通知状态的布尔值。事件对象包含人工重置事件对象和自动重置事件对象。

        人工重置事件对象:当该对象得到通知时,等待该对象的所有线程均变为可调度线程。并且需要调用ResetEvent函数手动设置事件对象为无信号状态。

        自动重置事件对象:当该对象得到通知时,等待该对象的所有线程,只有一个变为可调度线程。系统会自动设置该对象为无信号状态,当代码的保护执行完之后要调用SetEvent函数,将其设置为有信号。

        创建事件对象的函数原型如下:

CreateEvent(
LPSECURITY_ATTRIBUTES  lpEventAttributes,
BOOL  bManualReset,
BOOL  bInitialState,
LPCTSTR  lpName
);
bManualReset:指明是人工重置事件对象还是自动重置时间对象。

bInitialState:     指定对象的初始状态,有信号还是无信号。

        另外两个函数,SetEvent、ResetEvent为把指定对象设置为有信号状态、无信号状态。关于线程同步的例子如下:

#include 
#include 

DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);

int index = 0;
int tickets = 100;
HANDLE hEvent;

int main()
{
    HANDLE hThread1;
    HANDLE hThread2;
 
    //创建事件对象
	hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
    
	if(hEvent)
    {
        if (ERROR_ALREADY_EXISTS == GetLastError())
        {
            std::cout << "only one instance can run!" << std::endl;
            return 0;
        }
    }
     //创建线程

    hThread1 = CreateThread(NULL, 0, Fun1Proc, NULL, 0, NULL);
    hThread2 = CreateThread(NULL, 0, Fun2Proc, NULL, 0, NULL);
    
    CloseHandle(hThread1);   
    CloseHandle(hThread2);
    Sleep(4000);

    std::cout<< "now is the main thread in running\n";
	CloseHandle(hEvent);

	system("pause");
    return 0;
}
//线程1的入口函数
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    while (true)
    {
        
        WaitForSingleObject(hEvent, INFINITE);
        if (tickets>0)
        {
            Sleep(1); 
            std::cout << "thread1 sell ticket :" << tickets-- << std::endl;
			SetEvent(hEvent);
        }
        else
		{
			SetEvent(hEvent);
            break;
		}
    }
 
    return 0;
}
//线程2的入口函数
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
    while (true)
    {
      
        WaitForSingleObject(hEvent,INFINITE);
        if (tickets>0)
        {
            Sleep(1);
            std::cout << "thread2 sell ticket :" << tickets-- << std::endl;
			SetEvent(hEvent);
        }
		else
		{
			SetEvent(hEvent);
            break;
		}
    }
    
    return 0;
}
利用事件对象实现线程同步_第1张图片

一般情况下,为了实现线程间的同步,我们不使用人工重置事件对象,而是使用自动重置事件对象,并在初始时,将其设置为有信号状态。

你可能感兴趣的:(windows编程)