开源中文网

您的位置: 首页 > 编程开发 > C++语言编程 > 正文

线程同步-事件对象

来源:  作者:

这是整理孙鑫VC得到的关于线程同步方面的笔记.

n       事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
n       有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程
#include <windows.h>
#include <iostream.h>

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);

int tickets=100;
HANDLE g_hEvent;

void main()
{
       HANDLE hThread1;
       HANDLE hThread2;
       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
       CloseHandle(hThread1);
       CloseHandle(hThread2);
g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
/*
第二个参数设定了是用人工重置还是自动重置事件对象,TRUE为人工重置事件对象.
如果是非信号状态,必须把信号状态设置成有信号状态,可以把CreateEvent的第三个参数设置TRUE,也可以用SetEvent(g_hEvent);把时间对象设置成有信号状态。ResetEvent(g_hEvent)把事件对象设置成非信号状态,g_hEvent是一个全局的时间状态。 人工重至必须显式的设置有信号状态.
尽量不要用人工重置事件对象,因为会出现下面的问题
*/
  SetEvent(g_hEvent);//把互斥对象设置成有信号状态,但这时候所有的线程都变成有信号状态,所以每个线程前面需要用ResetEvent

       Sleep(4000);
       CloseHandle(g_hEvent);
}

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
       while(TRUE)
       {
              WaitForSingleObject(g_hEvent,INFINITE);
//            ResetEvent(g_hEvent);
/*
在这用ResetEvent把护持对象设置成非信号状态是不可以的,因为
1.       很可多个线程同时通过WaitForSingleObject,然后在这把互斥对象设置成非信号状态.
2.       在多cpu的情况下,这个时候可能多个线程已经分别进入了不同的cpu,从而使得互斥对象不起作用
*/.
              if(tickets>0)
              {
                     Sleep(1);
                     cout<<"thread1 sell ticket : "<<tickets--<<endl;
              }
              else
                     break;
              SetEvent(g_hEvent);
       }
     
       return 0;
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
     
       while(TRUE)
       {
              WaitForSingleObject(g_hEvent,INFINITE);
//            ResetEvent(g_hEvent);
/*
在这用ResetEvent把护持对象设置成非信号状态是不可以的,因为
3.       很可多个线程同时通过WaitForSingleObject,然后在这把互斥对象设置成非信号状态.
4.       在多cpu的情况下,这个时候可能多个线程已经分别进入了不同的cpu,从而使得互斥对象不起作用
*/.

              if(tickets>0)
              {
                     Sleep(1);
                     cout<<"thread2 sell ticket : "<<tickets--<<endl;
              }
              else
                     break;
              SetEvent(g_hEvent);
       }
     
       return 0;
}
自动重置护持对象例子
/*
自动重置事件对象,当事件对象为有信号状态的时候,等待该对象的线程只有一个能得到该事件对象,这时候系统会把他变成非信号状态,所以在这个线程运行结束之后,一定要用SetEvent把该事件对象重新设置成有信号状态
*/
#include <windows.h>
#include <iostream.h>

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);

int tickets=100;
HANDLE g_hEvent;

void main()
{
       HANDLE hThread1;
       HANDLE hThread2;
       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
       CloseHandle(hThread1);
       CloseHandle(hThread2);

       g_hEvent=CreateEvent(NULL,FALSE,FALSE,,NULL);
SetEvent(g_hEvent);
/*
把事件对象设置成有信号状态,当然这里也可以通过把CreateEvent的第三个参数设置成TRUE来实现
*/
       Sleep(4000);
       CloseHandle(g_hEvent);//关闭事件对象句柄
}

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
       while(TRUE)
       {
              WaitForSingleObject(g_hEvent,INFINITE);
              if(tickets>0)
              {
                     Sleep(1);
                     cout<<"thread1 sell ticket : "<<tickets--<<endl;
              }
              else
                     break;
              SetEvent(g_hEvent);//重新设置成有信号状态
       }
     
       return 0;
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
     
       while(TRUE)
       {
              WaitForSingleObject(g_hEvent,INFINITE);
              if(tickets>0)
              {
                     Sleep(1);
                     cout<<"thread2 sell ticket : "<<tickets--<<endl;
              }
              else
                     break;
              SetEvent(g_hEvent);
       }
     
       return 0;
}

/*
用它来实现只有一个实例运行的方法和用命名互斥对象的方法相同.
*/
代码片段:
void main()
{
       HANDLE hThread1;
       HANDLE hThread2;
       hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
       hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
       CloseHandle(hThread1);
       CloseHandle(hThread2);
       g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets");//设置成命名事件对象
       if(g_hEvent)
       {
              if(ERROR_ALREADY_EXISTS==GetLastError())
              {
                     cout<<"only instance can run!"<<endl;
                     return;
              }
       }
       SetEvent(g_hEvent);

       Sleep(4000);
       CloseHandle(g_hEvent);
}

Tags:线程 对象 事件
关于开源中文网 - 联系我们 - 广告服务 - 网站地图 - 版权声明