线程同步的几种方法

线程的同步之事件对象



介绍:事件对象也属于内核对象

组成:

1.使用计数

2.布尔值:指明是自动重置还是人工重置



两种不同类型的事件对象:

人工重置:当人工重置的事件对象得到通知时,等待该事件的所有线程均变为可调度线程

自动重置:当一个自动重置的事件得到通知时,等待该事件的线程只有一个线程变为可调度线程




创建事件对象:

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全性
  BOOL bManualReset,                       // 是人工重置还自动重置
  BOOL bInitialState,                      // 初始状态,为有信号还是没有
  LPCTSTR lpName                           // 事件对象的名称
);


这里需要注意的是参数2,如果为设置为TRUE表示人工重置,此时你必须手动重置此事件对象为非信号状态

BOOL ResetEvent(
  HANDLE hEvent   // handle to event
);

如果参数2FALSE,则等待线程被释放之后,系统自动重置事件对象为非信号状态(自动重置)



设置事件对象为有信号状态的方法:

1.在创建的时候指定第三个参数为TRUE

2.在创建的时候第三个参数为FALSE(非信号状态)

然后调用一个函数:

BOOL SetEvent(
  HANDLE hEvent   // handle to event
);

将事件对象设置为有信号状态



注意:在重点说明一下对于一个人工重置的事件对象,需要注意一点的是:当人工重置的事件对象为有信号状态时,等待该对象的所有线程均变为可调度状态


对于一个自动重置的事件对象来说,需要注意一点是:当自动重置的事件对象变为有信号状态时,等待该对象的线程只有一个变为可调度状态



命名的事件对象:

对于命名的事件对象A被创建后,如果你在其他线程中再次创建一个同名的事件对象时


调用GetLastError()后会返回ERROR_ALREADY_EXISTS


利用此功能可以实现同一应用程序只能有一个实例运行








线程的同步之临界区对象


打个比方,这里把临界区对象比作公用电话亭,

一个人进入公用电话亭就好比获得了临界区对象,此时其它人就不能再使用这个电话亭,直到你使用完为止(对应于线程中就是一旦某线程获得了临界区对象,其他线程就不能访问此临界区了直到此临界区对象被释放为止)





建立并初始化临界区对象

VOID InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection  // critical section
);



获得临界区对象

VOID EnterCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection  // critical section
);



释放临界区对象

VOID LeaveCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection   // critical section
);



释放临界区对象的所有资源

VOID DeleteCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection   // critical section
);



使用临界区对象可能会造成死锁问题:

线程的死锁:

线程1拥有了临界区对象A,等待临界区对象B,线程2拥有临界区对象B等待临界区对象A






互斥对象、事件对象和关键代码段的比较



互斥对象和事件对象属于内核对象,利用内核对象进行线程的同步,速度较慢,但是利用内核对象可以在多个进程的各个线程间进行同步



关键代码段是工作在用户模式下,同步速度较快,但是容易造成死锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值