2013-04-08 48 views
1

以下是我執行的SleepConditionVariableCSWakeAllConditionVariable和線程創建函數。問題是,有時當我嘗試創建線程時,創建線程卡在WaitForSingleObject(cv->mut, INFINITE);SleepConditionVariableCS中。我無法弄清楚這裏的競賽狀況。這段代碼中的競態條件是什麼?


typedef struct 
{ 
    int waiters_count; 
    HANDLE sema_; 
    HANDLE mut; 
} CONDITION_VARIABLE; 

void SleepConditionVariableCS(CONDITION_VARIABLE *cv, CRITICAL_SECTION *cs, int32_t dwMilliseconds){ 
    WaitForSingleObject(cv->mut, INFINITE); //Acuire object lock 

    cv->waiters_count++; 
    LeaveCriticalSection (cs); 
    if (SignalObjectAndWait(cv->mut, cv->sema_, dwMilliseconds, FALSE) == WAIT_TIMEOUT){ //SignalObjectAndWait releases the lock 
     cv->waiters_count--; 
    } 
    EnterCriticalSection(cs); 
} 

void WakeAllConditionVariable(CONDITION_VARIABLE *cv){ 
    WaitForSingleObject(cv->mut, INFINITE); 

    while (cv->waiters_count > 0){ 
     cv->waiters_count = cv->waiters_count - 1; 
     ReleaseSemaphore (cv->sema_, 1, 0); 
    } 
    ReleaseMutex(cv->mut); 
} 

void KernelThread_CreationWait(void *kthread){ 
    KernelThread *thread = (KernelThread *) kthread; 

    EnterCriticalSection(thread->lock); 
    thread->state = Thread_CREATED; 

    WakeAllConditionVariable(thread->condition_variable); 

    LeaveCriticalSection(thread->lock); 
    KernelThread_main(kthread); 
} 

KernelThread* createKernelThread(){ 
    EventHandler_getHandler(); 

    unsigned long threadid; 
    int t; 
    void *hand; 

    KernelThread *thread = KernelThread_malloc(); 
    EnterCriticalSection(thread->lock); 
    thread->state = Thread_WAITINGFORCREATION; 
    hand = CreateThread(NULL, 
      0, // security, stack size 
      (LPTHREAD_START_ROUTINE)&KernelThread_CreationWait, // start 
      (void *)thread, 
      0, 
      &threadid); // param, creation flags, id 
    if (hand == NULL){ 
     printf("ERROR: return handle from CreateThread() is NULL\n"); 
     exit(-1); 
    } 
    thread->thread = hand; 
    thread->thread_id = threadid; 

    SleepConditionVariableCS(thread->condition_variable,thread->lock,INFINITE); 
    LeaveCriticalSection(thread->lock); 

    return thread; 
} 

void InitializeConditionVariable (CONDITION_VARIABLE *cv){ 
    cv->waiters_count = 0; 
    cv->sema_ = CreateSemaphore (NULL,  // no security 
           0,   // initially 0 
           0x7fffffff, // max count 
           NULL);  // unnamed 
    cv->mut = CreateMutex(
      NULL,    // default security attributes 
      FALSE,    // initially not owned 
      NULL);    // unnamed mutex 
} 
+0

'''SleepConditionVariableCS'''你叫'''LeaveCriticalSection'''先'''EnterCriticalSection'''第二。氣味 – 2013-04-08 21:12:37

+0

@ user931794我知道,但我獲得了一個不同的鎖('cv-> mut')以彌補差距。這是必要的,因爲我不能同時睡覺和解鎖'CRITICAL_SECTION'。如果您明確知道錯誤的位置,那將會非常有幫助。 – chacham15 2013-04-08 21:15:57

+0

可能是一個愚蠢的問題,但是'thread-> condition_variable'被初始化了嗎? – simonc 2013-04-08 21:17:26

回答

1

在嘗試使用win32 apis實現pthread樣式條件變量時,請查看以下詳細分析。 http://www.cs.wustl.edu/~schmidt/win32-cv-1.html。 (尤其是第3.4節)。

在你的代碼中,我目前只看到一個問題。在SleepConditionVariableCS()

LeaveCriticalSection (cs); 
    if (SignalObjectAndWait(cv->mut, cv->sema_, dwMilliseconds, FALSE) == WAIT_TIMEOUT){ //SignalObjectAndWait releases the lock 
     // RIGHT HERE YOU HAVE NOT ACQUIRED cv->mut 
     cv->waiters_count--; // SO THIS IS A DATA RACE (with the cv->waiters_count uses in WakeAllConditionVariable() 
    } 
+0

這是一個很好的觀點,但是您是否知道如何糾正這一問題而不把它全部拋出並複製鏈接中的解決方案?在遞減之前(使用非零檢查)是否會輸入鎖定? – chacham15 2013-04-08 21:58:44

+0

這會照顧數據競賽。但是,你會遇到其他(不太可能和更微妙的)問題。例如,你超時,但在獲得cv-> mut之前,SleepConditionVariableCS()中的其他線程可能首先獲取cv-> mut,然後增加cv-> waiters_count。在這種情況下,我不能完全理解,但我認爲這並不好。 – 2013-04-08 22:10:52

+0

現在我想到了,這個錯誤是錯誤的,因爲睡眠是通過'INFINITE'調用的,因此返回值永遠不會是'WAIT_TIMEOUT'。 – chacham15 2013-04-08 22:11:25

0

我沒有看到真正突出的邏輯缺陷。

但是......

你初始化CONDITION_VARIABLE到已知狀態使用它之前?

你不檢查幾個系統調用的返回值,這可能會返回一個你永遠不會看到的錯誤。 WaitForSingleObjectEnterCriticalSection可以失敗或被給予錯誤的句柄。

你是否總是鎖定thread->lock並在處理條件變量時保持鎖定狀態?我看到2個不同的代碼片段,並參考了thread->lock

您是否每次都以相同的順序鎖定/解鎖臨界區域和區域?

+0

我明白這些都是最佳實踐,但是我給自己的代碼導致了競爭條件:'createKernelThread'功能塊等待已經過去的'WakeAllConditionVariable'信號。在該代碼中,您可以看到線程鎖被獲取並且在完成之前不會被釋放。我正在努力增加一些檢查,但是在檢查EnterCriticalSection後是無效的。 – chacham15 2013-04-08 21:25:17

+0

不,剛剛得到競爭條件並添加了錯誤檢查,沒有任何錯誤報告在「WaitForSingleObject」上。 – chacham15 2013-04-08 21:47:50