线程的重要特性就在于,如何让多个线程之间互相合作,而不是争吵罢工。
同步(synchronous):当程序1调用程序2时,程序1停下来不动,直到程序2完成回到程序1来,程序1才继续下去,那么两者的关系就是同步;
异步(asynchronous):如果程序1调用程序2时,经自继续自己的下一个动作,那么两者之间的关系就是异步;
win32中关于进程和线程的协调工作是由同步机制来完成。
临界区域:
所谓临界区域就是指用来处理一份被共享的资源的程序代码。
必须对临界区域进行保护,一次只能有一个线程获准进入该区域内进行操作。
一般代码中可以为需要保护的资源,声明一个CRITICAL_SECTION类型的变量,让其扮演红绿灯。
// 启动和关闭该变量
VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
// 占用和释放该变量
VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
该些接口可以被调用多次,当然,释放时也得释放多次。
不要长时间锁住一份资源:千万不要在一个临界区域之中调用sleep或者任何wait之类的API函数。
我们没办法获知临界区中的那个线程是生是死,由于临界区域不是核心对象,如果进入临界区域的那个线程突然DOWN掉了,而没有调用LeaveCriticalSection()的话,系统没有办法将该临界区清除。所以,更好的方法就是使用mutex。
死锁:
死锁就是线程互相等待。
避免死锁的方法就是寻找好的规约方法;
互斥(Mutex):
win32的mutex用途和临界区非常相似,但是它牺牲速度增加弹性。一个时间内只能够有一个线程拥有mutex。
1. 锁住一个未被拥有的mutex,比锁住一个未被拥有的临界区域变量需要花费更多的时间。
2. Mutex可以跨进程使用,但临界区域则只能够在一个进程中使用。
3. 等待一个mutex时,可以指定结束等待时间,避免占用者暴死现象。
产生一个互斥器(Mutex):
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
如果成功,则返回一个handle,否则返回null。调用GetLastError()可以获得进一步信息。
当你不再需要一个mutex时,可以使用CloseHandle()。