多线程的同步

来源:互联网 发布:网络销售计划书范文 编辑:程序博客网 时间:2024/05/16 07:47

       在windows中线程间同步的方式有多种包括创建事件对象,互斥对象,临界区等

一,创建事件对象

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

CreateEvent()

函数功能描述

  创建或打开一个命名的或无名的事件对象
      事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,
       另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。

函数原型:

  HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性
  BOOL bManualReset, // 复位方式
  BOOL bInitialState, // 初始状态
  LPCTSTR lpName // 对象名称
  );

参数:
  lpEventAttributes:

  [输入]一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承。如果lpEventAttributes是NULL,此句柄不能被继承。
  Windows NT/2000:lpEventAttributes的结构中的成员为新的事件指定了一个安全符。如果lpEventAttributes是NULL,事件将获得一个默认的安全符。
  bManualReset:
  [输入]指定将事件对象创建成手动复原还是自动复原。如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。如果设置为FALSE,当事件被一个等待线程请求到以后,系统将会自动将事件状态复原为无信号状态。
  bInitialState:
  [输入]指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
  lpName:
  [输入]指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。
  如果lpName指定的名字,与一个存在的命名的事件对象的名称相同,函数将请求EVENT_ALL_ACCESS来访问存在的对象。这时候,由于bManualReset和bInitialState参数已经在创建事件的进程中设置,这两个参数将被忽略。如果lpEventAttributes是参数不是NULL,它将确定此句柄是否可以被继承,但是其安全描述符成员将被忽略。
  如果lpName为NULL,将创建一个无名的事件对象。
  如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文件映射对象名称相同,函数将会失败,在GetLastError函数中将返回ERROR_INVALID_HANDLE。造成这种现象的原因是这些对象共享同一个命名空间。

返回值

  如果函数调用成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。
  如果函数失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError。
注备:当该事件为手动复原时,一旦该事件对象为有信号状态,所有等待该事件对象的线程均变为可调度线程,直到手工调用ResetEvent(HANDLE)该事件对象才变为无信号状态当该事件为自动复原时,一旦该事件对象为有信号状态,所有等待该事件对象的线程中只有一个线程(A)为可调度线程,并且一旦A请求到事件对象系统立马将事件对象设置为无信号状态。

                用SetEvent(HANDLE)可将事件对象设置为有信号状态。

例如:

HANDLE g_xEvent = CreateEvent(NULL , FALSE , FALSE , NULL);

SetEvent(g_xEvent);

waitforsingleobject(handle , INFINITE); 

.

.

被保护的代码段

SetEvent(g_xEvent);

二. 创建互斥对象

       互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量,一个线程ID和一个计数器。ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。没有线程拥有互斥对象时其处于有信号状态,否则其处于无信号状态。

CreateMutex();

HANDLE CreateMutex(

  LPSECURITY_ATTRIBUTES  lpMutexAttributes, // 指向安全属性的指针
  BOOL  bInitialOwner, // 初始化互斥对象的所有者
  LPCTSTR lpName // 指向互斥对象名的指针
  );

创建一个有名或无名的互斥对象; lpMutexAttributes为NULL时互斥对象为默认安全属性,不能被子进程继承;bInitialOwner为true时调用线程拥有互斥对象,互斥对象处于无信号状态,为false时没有线程拥有互斥对象,互斥对象处于有信号状态,其线程ID为0;lpName为NULL时为匿名互斥对象。

返回值:返回互斥对象的句柄

例如:

HANDLE handle = createmutex(null , false , null);

waitforsingleobject(handle ,INFINITE);  申请互斥对象,得到互斥对象后才能返回,否则一直等待,得到互斥对象后互斥对象变为无信号状态

.

.

被保护的代码段

ReleaseMutex(handle);     将互斥对象的线程ID设为0,释放互斥对象,变为有信号状态

createmutex(),waitforsingleobject()处于同一个线程即互斥对象的线程ID与申请互斥对象的线程ID相同时,这时(互斥对象无信号)waitforsingleobject()也能成功,互斥对象的计数器变为2.


三,创建临界区

1.CRITICAL_SECTION  c_st;    //设置临界区对象

2. void InitializeCriticalSection(&c_st);     //初始化临界区对象

3.void EnterCriticalSection(&c_st) ;     // 判断是否可拥有临界区所有权,若可拥有,则进入(EnterCriticalSection(&c_st)立即返回) ,否则线程等待(EnterCriticalSection(&c_st)不立即返回)。

4.void LeaveCriticalSection(&c_st);      //释放临界区对象

5.DeleteCriticalSection(&c_st);          //当不再需要临界区对象时释放临界区对象所拥有的资源




原创粉丝点击