多线程--同步(事件Event)

来源:互联网 发布:raphael min.js 编辑:程序博客网 时间:2024/05/22 15:06

事件分为两类:人工重置, 自动重置

人工重置时,所有等待线程都变为有信号状态。并且持续保持有信号状态,除非显式调用ResetEvent(g_hEvent);
自动重置则不。所以人工重置不利于做线程同步。

创建事件 g_hEvent = CreateEvent(NULL, false, false, NULL);

param1:安全级别,设置为NULL, 取得默认值

param2:人工重置(true), 自动重置(false)

param3:事件状态 有信号(true)  无信号(false)

param4:事件名称,如果匿名设置为NULL

一般采用自动重置方式。如果事件状态如果设置为false要使用SetEvent(g_hEvent);设置为有信号

设置为有信号 SetEvent(g_hEvent);

 设置为无信号 ReSetEvent(g_hEvent);

 

#i nclude <windows.h>
#i nclude <iostream.h>

extern int tickets;

//事件对象
HANDLE  g_hEvent;

DWORD WINAPI thread_Event_Fun1Proc(
LPVOID lpParameter)
{
 while (true) {
  WaitForSingleObject(g_hEvent, INFINITE);  //取得事件对象
  if (tickets>0) {
   Sleep(1);
   cout<<"thread1: "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);  //设置为有信号
 }
 return 0;
}

DWORD WINAPI thread_Event_Fun2Proc(
LPVOID lpParameter)
{
 while (true) {
  WaitForSingleObject(g_hEvent, INFINITE);  //取得事件对象
  if (tickets>0) {
   cout<<"thread2: "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);  //设置为有信号
 }
 return 0;
}

void thread_Event()
{
 HANDLE handle1 = CreateThread(NULL, 0, thread_Event_Fun1Proc, NULL, 0, NULL);
 HANDLE handle2 = CreateThread(NULL, 0, thread_Event_Fun2Proc, NULL, 0, NULL);
 CloseHandle(handle1);
 CloseHandle(handle2);
 
 //创建事件对象
 //第2参数指设置为非人工重置(false) (注意不要使用人工方式,比较麻烦)
 //第3参数指设置为无信号(false)
    g_hEvent = CreateEvent(NULL, false, false, NULL);

 //设置为有信号
 SetEvent(g_hEvent);

 //设置为无信号
 //ReSetEvent(g_hEvent);
 Sleep(200);

CloseHandle(g_hEvent);
}

void main()
{
 thread_Event();
 cout<<"++Event++"<<endl;
}

 

命名事件对象

void thread_Event()
{
 HANDLE handle1 = CreateThread(NULL, 0, thread_Event_Fun1Proc, NULL, 0, NULL);
 HANDLE handle2 = CreateThread(NULL, 0, thread_Event_Fun2Proc, NULL, 0, NULL);
 CloseHandle(handle1);
 CloseHandle(handle2);
 
 //创建事件对象
 //第2参数指设置为非人工重置(false) (注意不要使用人工方式,比较麻烦)
 //第3参数指设置为无信号(false)
    g_hEvent = CreateEvent(NULL, false, false, "tickets");

//程序只能有一个实例
if(g_hEvent)
{
  if (ERROR_ALREADY_EXISTS == GetLastError()) {
           cout<<"app alreadly run."<<endl;
           return;
  }
}

 //设置为有信号
 SetEvent(g_hEvent);

 //设置为无信号
 //ReSetEvent(g_hEvent);
 Sleep(200);
 CloseHandle(g_hEvent);
}
 

上面程序建立命名事件,在多个进程中可以使用。上面就是在一个进程中判断命名事件对象是否已经存在,如果存在,就拒绝线程继续执行。
这样。当两个线程同时运行时,就会提示已经有一个线程运行。

 

//事件

#i nclude <windows.h>
#i nclude <iostream.h>

extern int tickets;

//临界区对象
HANDLE  g_hEvent;

DWORD WINAPI thread_Event_Fun1Proc(
LPVOID lpParameter)
{
 while (true) {
  WaitForSingleObject(g_hEvent, INFINITE);  //取得事件对象
  if (tickets>0) {
   Sleep(1);
   cout<<"thread1: "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);  //设置为有信号
 }
 return 0;
}

DWORD WINAPI thread_Event_Fun2Proc(
LPVOID lpParameter)
{
 while (true) {
  WaitForSingleObject(g_hEvent, INFINITE);  //取得事件对象
  if (tickets>0) {
   cout<<"thread2: "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);  //设置为有信号
 }
 return 0;
}

void thread_Event()
{
 HANDLE handle1 = CreateThread(NULL, 0, thread_Event_Fun1Proc, NULL, 0, NULL);
 HANDLE handle2 = CreateThread(NULL, 0, thread_Event_Fun2Proc, NULL, 0, NULL);
 CloseHandle(handle1);
 CloseHandle(handle2);
 
 //创建事件对象
    g_hEvent = CreateEvent(NULL, false, false, NULL);

 //设置为有信号
 SetEvent(g_hEvent);
 Sleep(200);
}

void main()
{
 thread_Event();
 cout<<"++Event++"<<endl;
}

 

HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,   安全选项
BOOL bManualReset,   true:人工方式(一般不要使用), false:自动方式
BOOL bInitialState,        true:初始有信号, false:初始无信号
LPTSTR lpName);         事件名字,如果匿名为NULL

BOOL bManualReset
如果设置事件为人式方式,则事件对所有线程表现为有信号状态,如果为自动方式,对所有线程表现为无信号状态
如果设置为人工方式,
在WaitForSingleObject(g_hEvent, INFINITE);  后调用 ResetEvent(g_hEvent)设置为无信息状态,但如果在两句之间切换CPU时间,仍然达不到同步的目的。所以在做线程同步时不要用人式方式。

如果设置为自动方式,
WaitForSingleObject(g_hEvent, INFINITE);  后则表现为无信号状态,在使用完资源后,再调用SetEvent(g_hEvent);设置为有信息状态,释放资源。

BOOL bInitialState,
如果初始设置为false, 为无信息状态, 在事件创建完成后,可以调用SetEvent设置为有信息状态,以让线程函数调用

BOOL SetEvent(
HANDLE hEvent );
设置为有信号状态

BOOL ResetEvent(
HANDLE hEvent );
设置为无信号状态

原创粉丝点击