学到的API函数
一、线程
创建线程、结束线程、获取线程的结束码
CreateThread
ExitThread
GetExitCodeThread
二、线程结束时触发
创建线程之后,等待线程的结束之后,再继续执行
WaitForSingleObject
创建多个线程之后,等待一组线程(或其中的一个)结束,再继续执行
WaitForMultipleObjects
将消息循环与内核对象的等待合并
MsgWaitForMultipleObjects
三、同步
SendMessage 是同步的
PostMessage 是异步的
1、临界区
初始化和销毁临界区的变量
InitializeCriticalSection
DeleteCriticalSection,不同于delete操作的释放内存
2、进入和离开临界区
临界区变量初始化之后,可以进入,然后可以离开
EnterCriticalSection
LeaveCriticalSection
一旦调用EnterCriticalSection进入某变量的临界区之后,仍然可以再次调用EnterCriticalSection进入该变量的临界区。但进入多少次,也要Leave多少次,该临界区才能被销毁。
临界区中不要调用Sleep或Wait...函数
临界区的不足:如果进入了临界区的线程结束了,而没有调用离开临界区的函数,该临界区将无法被销毁掉;而系统或其他线程是无法知道进入临界区的线程是否已经结束
避免这个不足,需要使用mutex
3、死锁
当有一段代码需要2个或更多资源(也就是至少进入两次临界区)时,可能会发生死锁
"all-or-nothing"(要不统统获得,要不统统没有),可以阻止死锁的发生
4、Mutex
Mutex的使用过程:
CreateMutex(创建Mutex时如果指定名称,则可以在进程间使用同一个Mutex。由于该名称整个操作系统都可以访问,所以需要避免重名)
OpenMutex
WaitForSingleObject 或 WaitForMultiObjects 或 MsgWaitForMultiObjects
ReleaseMutex
CloseHandle
5、信号量
等待一个数量为n的资源,当n=0时,就必须等待;使用,使n-1;释放,使n+1。如果n=1,就是Mutex。
CreateSemaphore 创建信号量(可以包含名称参数)
然后利用Wait...()函数可以锁定一个Semaphore
ReleaseSemaphore
请记住, lpPreviousCount 参数所传回来的是一个瞬间值。你不可以把lReleaseCount 加上 *lpPreviousCount,就当作是 semaphore 的现值,因为其他线程可能已经改变了 semaphore 的值。
6、事件
CreateEvent 创建事件
SetEvent 设置事件为激发状态
ResetEvent 设置事件为非激发状态(注意:不是重新设置为激发状态)
PulseEvent 如果是手动的ResetEvent,设置为激发状态后,则唤醒所有等待中的线程,然后变为非激发状态;如果是自动档ResetEvent,设置为激发状态后,则一个一个地唤醒等待中的线程
弊端:
1)激发event时没有线程在等待,则该event会被遗失
2)容易造成死锁
7、InterLocked变量
对于简单变量的互斥操作(比如计数器),如果用临界区或Mutex,相对来说会比较占用资源(相对计算器加1的操作而言),于是InterLocked变量出现了
InterlockedIncrement 值加1
InterlockedDecrement 值减1
InterlockedExchange 传入新值,返回旧值
四、线程控制
1、结束线程
TerminateThread 结束线程
缺点:
1)未给被结束线程一个清理自己内存的机会,或者被结束
2)导致内存泄漏
3)线程正进入临界区,则该临界区将永远处于锁定状态
2、线程优先权