天天看點

研究條件變量pthread_cond_wait的機制

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 ”便不再成立,鍊路檢測線程的代碼繼續往下走。

繼續閱讀