多线程(进程)的同步对象

来源:互联网 发布:全网通是什么网络制式 编辑:程序博客网 时间:2024/05/16 11:58

-------------------临界区-------------------
critical section不是核心对象,没有handle。
因此它有一个缺陷,就是无法确定进入临界区的线程是否已经结束或死掉。如果进入临界区的线程死掉了但没有调用leave操作,那么系统无法把这个临界区清除。
另一个缺陷是,如果做一件事需要同时进入两个临界区时,就可能出现死锁。而这时却不能使用WaitForMultipleObjects()函数来一次获得两个锁。
也因此有一个优势,进入临界区操作的时间比核心同步对象快很多。

特点:
只能在同一个进程中使用。
不能一次等待多个临界区。

对同一个临界区,在一对EnterCriticalSection()和LeaveCriticalSection()之间,可以嵌套多层该临界区的Enter和Leave。
即一个线程一旦进入一个临界区,它就可以多次进入,但必须要保证有相应次数的离开操作。

critical section的使用:
InitializeCriticalSection()
EnterCriticalSection()
LeaveCriticalSection()
DeleteCriticalSection()

-------------------互斥量-------------------
互斥量是核心对象,有handle。
锁住一个互斥量需要的时间,相当于100倍锁住一个临界区的时间。

特点:
1、可以跨进程使用。(命名互斥量)
2、等待一个互斥量时,可以指定等待结束时间。
3、只能被拥有它的进程(线程)释放。
4、如果线程在拥有一个mutex之后,没有ReleaseMutex()就结束了,则mutex不会被销毁,为被视为“未被拥有”以及“未被激发”,下一个等待操作会返回WAIT_ABANDONED_0。(对waitformultipleobjects()则返回WAIT_ABANDONED_x)。
5、拥有一个mutex后,反复多次调用wait操作,也不会被阻塞。

如果调用CreateMutex()并指定一个已经存在的mutex的名字,则系统会返回这个已经存在的mutex的handle,而不是重新创建一个新的。

如果mutex未被任何线程(或进程)拥有,则mutex处于激发状态(有信号状态)。(准确地说,是未被拥有且被wait时,处于激发状态。)

核心对象的handle有引用计数。在其计数降为0时被操作系统销毁。
拥有核心对象handle的线程结束时(或调用CloseHandle()),该handle的计数会减少1。(线程结束,系统会自动释放该线程拥有的handle ???)

mutex的使用:
CreateMutex()/OpenMutex()
WaitForSingleObject()/WaitForMultipleObjects()/MsgWaitForMultipleObjects()
ReleaseMutex()
CloseHandle()

-------------------------信号量-----------------------
是核心对象,有handle。
是解决生产者/消费者问题的常用方法。比如环状缓冲区。
信号量可以表达资源的数量,所以适合管理一组相同的资源。
mutex是semaphore的特例,是只有一个资源的semaphore。mutex也称为binary semaphore。

特点:
1、可以指定名字。
2、可以跨线程使用。
3、没有拥有者。没有拥有权的概念,可以被多个线程锁定。也可以被一个线程反复多次锁定(是多个锁定)。
4、可以被任何线程(进程)释放。调用ReleaseSemaphore()的线程,可以不必是wait操作的那个线程。即任何线程都可以释放信号量。

在CreateSemaphore()时,如果指定名字的信号量已经存在,函数仍然可以成功(和mutex的创建相同),但GetLastError()返回ERROR_ALREADY_EXISTS。

信号量的使用:
CreateSemaphore()
WaitForSingleObject()/WaitForMultipleObjects()/MsgWaitForMultipleObjects()
ReleaseSemaphore()
CloseHandle()

----------------------------事件-------------------------
是核心对象,有handle。

特点:
可以自己控制事件对象的状态(有无信号状态)。可以和mutex、semaphore不一样,状态的变化可不是因为wait操作导致。(在创建时设置为手动reset)。
可以有名字。可以跨线程。

在CreateEvent()时,如果指定名字的事件已经存在,函数仍然可以成功(和mutex的创建相同),但GetLastError()返回ERROR_ALREADY_EXISTS。

事件的用法:
CreteEvent()
SetEvent()/PulseEvent()
WaitForSingleObject()/WaitForMultipleObjects()/MsgWaitForMultipleObjects()
ResetEvent()
CloseHandle()

PulseEvent(): 把事件设置为激发状态(有信号状态)。
当事件为ManualReset时,会唤醒所有等待这个事件的线程。
当事件为AutoReset时,会唤醒其中一个等待这个事件的线程。

如果没有线程正在等待,那么PulseEvent()操作产生的激发状态不会被储存,造成事件丢失。即激发是瞬时状态。如果问题的解决方案中存在事件丢失造成程序错误这种可能,则可以使用semaphore。

---------------Interlocked函数--------------

它没有等待的功能,只完成对int数据的原子化操作。

InterlockedDecrement(): 把参数减1,然后和0比较,如果大于0返回正数,如果等于0返回0,如果小于0返回负数。
InterlockedIncrement(): 同上。

InterlockedExchange(LPLONG lpTarget, LONG lValue);
0 0