1條件變量的解釋:
條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而挂起;另一個線程使"條件成立"(給出條件成立信号)。為了防止競争,條件變量的使用總是和一個互斥鎖結合在一起。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
等待條件有兩種方式:條件等待pthread_cond_wait()和計時等待pthread_cond_timedwait(),其中計時等待方式如果在給定時刻前條件沒有滿足,則傳回ETIMEDOUT,結束等待,其中abstime以與time()條件變量相同意義的絕對時間形式出現,表示格林尼治時間1970年1月1日0時0分0秒。
無論哪種等待方式,都必須和一個互斥鎖配合,以防止多個線程同時請求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的競争條件(Race Condition)。mutex互斥鎖必須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或者适應鎖(PTHREAD_MUTEX_ADAPTIVE_NP),且在調用pthread_cond_wait()前必須由本線程加鎖(pthread_mutex_lock()),而在更新條件等待隊列以前,mutex保持鎖定狀态,并線上程挂起進入等待前解鎖。在條件滿足進而離開pthread_cond_wait()之前,mutex将被重新加鎖,以與進入pthread_cond_wait()前的加鎖動作對應。阻塞時處于解鎖狀态。
激發條件有兩種形式,pthread_cond_signal()激活一個等待該條件的線程,存在多個等待線程時按入隊順序激活其中一個;而pthread_cond_broadcast()則激活所有等待線程。
2對pthread_cond_wait測試
2.1方法:
在某多線程檔案轉發協定的代碼裡加上日志和睡眠時間進行測試。配置TCP_THREAD_NUM=5 。
* 函數名稱:InitTcpThread
* 功能描述:建立鍊路檢測的線程和鎖
BOOLEAN InitTcpThread()
{
......
LOG("TEST1 InitTcpThread gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);
//等待處理線程池ready ok,隻能在一個線程中等待
pthread_mutex_lock(&gInitLock);
while (gInitCount < TCP_THREAD_NUM)
{
LOG("TEST2 InitTcpThread gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);
pthread_cond_wait(&gInitCond, &gInitLock);
LOG("TEST3 InitTcpThread gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);
}
pthread_mutex_unlock(&gInitLock);
LOG("TEST4 InitTcpThread gInitCount:%d,TCP_THREAD_NUM:%d.",gInitCount,TCP_THREAD_NUM);
......
}
......
}
* 函數名稱:tcpChkLinkTaskProc
* 功能描述:HTTP SA工作線程
VOID tcpChkLinkTaskProc(LPVOID lpPno)
{
......
sleep(1);
LOG(" TEST1 tcpChkLinkTaskProc gInitCount:%d. ",gInitCount);
//條件變量,通知listening thread
pthread_mutex_lock(&gInitLock);
LOG(" TEST2 tcpChkLinkTaskProc gInitCount:%d. ",gInitCount);
sleep(1);
gInitCount++;
LOG(" TEST3 tcpChkLinkTaskProc gInitCount:%d. ",gInitCount);
pthread_cond_signal(&gInitCond);
LOG(" TEST4 tcpChkLinkTaskProc gInitCount:%d. ",gInitCount);
pthread_mutex_unlock(&gInitLock);
LOG(" TEST5 tcpChkLinkTaskProc gInitCount:%d. ",gInitCount);
......
}
2.2測試日志
18-03-29 12:51:52:189 [TEST1 InitTcpThread gInitCount:0,TCP_THREAD_NUM:5.]
18-03-29 12:51:52:189 [TEST2 InitTcpThread gInitCount:0,TCP_THREAD_NUM:5.]
18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0. ]
18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0. ]
18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0. ]
18-03-29 12:51:53:189 [ TEST1 tcpChkLinkTaskProc gInitCount:0. ]
18-03-29 12:51:53:189 [ TEST2 tcpChkLinkTaskProc gInitCount:0. ]
18-03-29 12:51:53:190 [ TEST1 tcpChkLinkTaskProc gInitCount:0. ]
18-03-29 12:51:54:190 [ TEST3 tcpChkLinkTaskProc gInitCount:1. ]
18-03-29 12:51:54:190 [ TEST4 tcpChkLinkTaskProc gInitCount:1. ]
18-03-29 12:51:54:190 [ TEST5 tcpChkLinkTaskProc gInitCount:1. ]
18-03-29 12:51:54:190 [ TEST2 tcpChkLinkTaskProc gInitCount:1. ]
18-03-29 12:51:55:190 [ TEST3 tcpChkLinkTaskProc gInitCount:2. ]
18-03-29 12:51:55:190 [ TEST4 tcpChkLinkTaskProc gInitCount:2. ]
18-03-29 12:51:55:190 [ TEST5 tcpChkLinkTaskProc gInitCount:2. ]
18-03-29 12:51:55:190 [ TEST2 tcpChkLinkTaskProc gInitCount:2. ]
18-03-29 12:51:56:191 [ TEST3 tcpChkLinkTaskProc gInitCount:3. ]
18-03-29 12:51:56:191 [ TEST4 tcpChkLinkTaskProc gInitCount:3. ]
18-03-29 12:51:56:191 [ TEST5 tcpChkLinkTaskProc gInitCount:3. ]
18-03-29 12:51:56:191 [ TEST2 tcpChkLinkTaskProc gInitCount:3. ]
18-03-29 12:51:57:191 [ TEST3 tcpChkLinkTaskProc gInitCount:4. ]
18-03-29 12:51:57:191 [ TEST4 tcpChkLinkTaskProc gInitCount:4. ]
18-03-29 12:51:57:191 [ TEST5 tcpChkLinkTaskProc gInitCount:4. ]
18-03-29 12:51:57:191 [ TEST2 tcpChkLinkTaskProc gInitCount:4. ]
18-03-29 12:51:58:191 [ TEST3 tcpChkLinkTaskProc gInitCount:5. ]
18-03-29 12:51:58:191 [ TEST4 tcpChkLinkTaskProc gInitCount:5. ]
18-03-29 12:51:58:191 [ TEST5 tcpChkLinkTaskProc gInitCount:5. ]
18-03-29 12:51:58:191 [TEST3 InitTcpThread gInitCount:5,TCP_THREAD_NUM:5.]
18-03-29 12:51:58:192 [TEST4 InitTcpThread gInitCount:5,TCP_THREAD_NUM:5.]
18-03-29 12:51:58: [InitTcpThread--Index[0]:host[10.46.181.23] port[5881]]
18-03-29 12:51:58: [InitTcpThread--ListenThreadNum[1] WorkThreadNum[5]]
2.3分析
pthread_cond_wait 内部自帶解鎖和加鎖,在InitTcpThread 建立鍊路檢測的線程和鎖函數 調用它之前必須求本線程加鎖(pthread_mutex_lock(&gInitLock) ),剛進入 pthread_cond_wait 時gInitCount =0 ,随後 pthread_cond_wait 解鎖 &gInitLock 并等待條件滿足。之後,tcpChkLinkTaskProc HTTP SA 工作線程的五個線程以此起來( 對 gInitLock 加鎖, gInitCount 自增, pthread_cond_signal(&gInitCond) 發信号給等待線程,對 gInitLock 解鎖),第五個信号發出後InitTcpThread 鍊路檢測的線程裡的“gInitCount < TCP_THREAD_NUM ”便不再成立,鍊路檢測線程的代碼繼續往下走。