您的位置:首页 > 编程语言

Windows 多线程编程总结

2013-08-04 22:10 218 查看
Windows多线程编程主要涉及的四个对象分别是:关键段CS,互斥量Mutex,信号量Semaphore ,事件Event 。其中多线程间互斥访问主要使用关键段CS,互斥量Mutex完成。多线程间的同步使用信号量Semaphore ,事件Event来完成。

关键段CS与互斥量Mutex都是完成多线程间的互斥,但是两者的区别是:互斥量可以完成不同进程的线程间的对资源的互斥访问。而关键段CS只能够完成同一进程的不同线程间的互斥。而且互斥量能完成对于线程访问互斥资源而异常退出没有释放互斥锁的情况。

信号量Semaphore 与事件Event都能完成线程间的同步,但是信号量Semaphore是每次触发加1,每次执行减1,如果信号量为0就不在执行了。而事件Event只要设置了事件为执行状态,只要不设置事件为退出状态,监听这一事件的所有线程都会执行。

关键段CS介绍和使用:

关键段CRITICAL_SECTION一共就四个函数,使用很是方便。下面是这四个函数的原型和使用说明。函数功能:初始化函数原型:void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);函数说明:定义关键段变量后必须先初始化。函数功能:销毁函数原型:void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);函数说明:用完之后记得销毁。函数功能:进入关键区域函数原型:void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);函数说明:系统保证各线程互斥的进入关键区域。函数功能:离开关关键区域函数原型:void LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);互斥量Mutex介绍和使用:第一个CreateMutex函数功能:创建互斥量(注意与事件Event的创建函数对比)函数原型:HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,BOOLbInitialOwner, LPCTSTRlpName);函数说明:第一个参数表示安全控制,一般直接传入NULL。第二个参数用来确定互斥量的初始拥有者。如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触发状态。如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,这意味互斥量不为任何线程占用,处于触发状态。第三个参数用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。函数访问值:成功返回一个表示互斥量的句柄,失败返回NULL。第二个打开互斥量函数原型:HANDLEOpenMutex(DWORDdwDesiredAccess,BOOLbInheritHandle,LPCTSTRlpName //名称);函数说明:第一个参数表示访问权限,对互斥量一般传入MUTEX_ALL_ACCESS。详细解释可以查看MSDN文档。第二个参数表示互斥量句柄继承性,一般传入TRUE即可。第三个参数表示名称。某一个进程中的线程创建互斥量后,其它进程中的线程就可以通过这个函数来找到这个互斥量。函数访问值:成功返回一个表示互斥量的句柄,失败返回NULL。第三个触发互斥量函数原型:BOOLReleaseMutex (HANDLEhMutex)函数说明:访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,其它线程可以开始访问了。最后一个清理互斥量由于互斥量是内核对象,因此使用CloseHandle()就可以ReleaseMutex()触发互斥量前就意外终止了(相当于该互斥量被“遗弃”了),那么所有等待这个互斥量的线程是否会由于该互斥量无法被触发而陷入一个无穷的等待过程中了?这显然不合理。因为占用某个互斥量的线程既然终止了那足以证明它不再使用被该互斥量保护的资源,所以这些资源完全并且应当被其它线程来使用。因此在这种“遗弃”情况下,系统自动把该互斥量内部的线程ID设置为0,并将它的递归计数器复置为0,表示这个互斥量被触发了。然后系统将“公平地”选定一个等待线程来完成调度(被选中的线程的WaitForSingleObject()会返回WAIT_ABANDONED_0)。信号量Semaphore 的介绍和使用抽象的来讲,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程/进程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,要么一直等下去(指放入阻塞队列),直到信号量大于等于一时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为释放了由信号量守护的资源。第一个CreateSemaphore函数功能:创建信号量函数原型:HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCTSTR lpName);函数说明:第一个参数表示安全控制,一般直接传入NULL。第二个参数表示初始资源数量。第三个参数表示最大并发数量。第四个参数表示信号量的名称,传入NULL表示匿名信号量。第二个 OpenSemaphore函数功能:打开信号量函数原型:HANDLE OpenSemaphore(DWORD dwDesiredAccess,BOOL bInheritHandle,LPCTSTR lpName);函数说明:第一个参数表示访问权限,对一般传入SEMAPHORE_ALL_ACCESS。详细解释可以查看MSDN文档。第二个参数表示信号量句柄继承性,一般传入TRUE即可。第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个信号量。第三个 ReleaseSemaphore函数功能:递增信号量的当前资源计数函数原型:BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount, LPLONG lpPreviousCount );函数说明:第一个参数是信号量的句柄。第二个参数表示增加个数,必须大于0且不超过最大资源数量。第三个参数可以用来传出先前的资源计数,设为NULL表示不需要传出。注意:当前资源数量大于0,表示信号量处于触发,等于0表示资源已经耗尽故信号量处于末触发。在对信号量调用等待函数时,等待函数会检查信号量的当前资源计数,如果大于0(即信号量处于触发状态),减1后返回让调用线程继续执行。一个线程可以多次调用等待函数来减小信号量。 最后一个 信号量的清理与销毁由于信号量是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。事件Event介绍和使用第一个CreateEvent函数功能:创建事件函数原型:HANDLECreateEvent(LPSECURITY_ATTRIBUTESlpEventAttributes,BOOLbManualReset,BOOLbInitialState,LPCTSTRlpName);函数说明:第一个参数表示安全控制,一般直接传入NULL。第二个参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。打个小小比方,手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。第三个参数表示事件的初始状态,传入TRUR表示已触发。第四个参数表示事件的名称,传入NULL表示匿名事件。第二个OpenEvent函数功能:根据名称获得一个事件句柄。函数原型:HANDLEOpenEvent(DWORDdwDesiredAccess,BOOLbInheritHandle,LPCTSTRlpName //名称);函数说明:第一个参数表示访问权限,对事件一般传入EVENT_ALL_ACCESS。详细解释可以查看MSDN文档。第二个参数表示事件句柄继承性,一般传入TRUE即可。第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个事件。第三个SetEvent函数功能:触发事件函数原型:BOOLSetEvent(HANDLEhEvent);函数说明:每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态。第四个ResetEvent函数功能:将事件设为末触发函数原型:BOOLResetEvent(HANDLEhEvent);最后一个事件的清理与销毁由于事件是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。WaitForSingleObject介绍:使用该函数监听事件和信号量的触发,对于信号量的触发可以使信号量的值减1.该函数每次只能监听一个对象。DWORD WINAPI WaitForSingleObject(__in HANDLE hHandle,__in DWORD dwMilliseconds);hHandle[in]对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。当等待仍在挂起状态时,句柄被关闭,那么函数行为是未定义的。该句柄必须具有 SYNCHRONIZE 访问权限。dwMilliseconds[in]定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。WaitForMultipleObjects介绍:使用该函数监听事件和信号量的触发,对于信号量的触发可以使信号量的值减1.该函数每次只能监听多个对象。DWORD WaitForMultipleObjects( DWORD nCount,const HANDLE* lpHandles,BOOL bWaitAll,DWORD dwMilliseconds);当WaitForMultipleObjects等到多个内核对象的时候,如果它的bWaitAll 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发,这个函数返回的只是其中序号最小的那个。如果为TRUE 则等待所有信号量有效在往下执行。(FALSE 当有其中一个信号量有效时就向下执行)如果函数成功,返回值表示该事件导致该函数返回。这个值可以是下列之一。ValueMeaningWAIT_OBJECT_0到(WAIT_OBJECT_0 + nCount - 1如果bWaitAll为TRUE),则返回值表明所有指定对象的状态信号。如果bWaitAll为FALSE,则返回值减去不是WAIT_OBJECT_0表示lpHandles数组的对象的满意指数的等待。如果多个对象在通话过程中信号成为,这是与所有的信号对象的最小索引值的信号对象的数组索引。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息