2011-11-03 64 views
1

我正在製作一個遊戲,用戶在這臺計算機上玩遊戲。電腦對手在輪到玩家的時候會考慮下一步的行動。如果玩家移動到計算機對手計劃移動的地點,則計算機對手再次開始搜索其移動。C++遊戲:pthread_cond_signal不會喚醒對手線程

這裏的主要功能的輪廓和對手功能:

[增訂]

pthread_mutex_t mutex; 
pthread_cond_t cond; 

int main() { 
    // ... initialize game variables, args to pass to opponent ... 

    pthread_t thread; 
    pthread_create(&thread, NULL, opponent, &args); 
    pthread_mutex_init(&mutex, NULL); 
    pthread_cond_init(&cond, NULL); 

    while(!isGameOver()) { 
     pthread_mutex_lock(&mutex); 

     if(getCurrentPlayer() != PLAYER) { 
      pthread_cond_wait(&cond, &mutex); 
     } 

     if(getCurrentPlayer() == PLAYER) { 
      // ... update board with player's move ... 

      setCurrentPlayer(OPPONENT); 

      pthread_cond_signal(&cond); 
     } 

     pthread_mutex_unlock(&mutex); 
    } 
} 

void * opponent(void * args) { 
    // initialize move to something invalid 

    while(!isGameOver()) { 
     if(!isValid(move)) { 
      move = findMove(); 
     } 

     pthread_mutex_lock(&mutex); 

     if(getCurrentPlayer() != OPPONENT) { 
      pthread_cond_wait(&cond, &mutex); 
     } 

     if(getCurrentPlayer() == OPPONENT) { 
      if(isValid(move)) { 
       // ... update board with opponent's move ... 

       setCurrentPlayer(PLAYER); 

       pthread_cond_signal(&cond); 
      } 
     } 

     pthread_mutex_unlock(&mutex); 
    } 
} 

目前,好像這是發生了什麼事:[增訂]

  • 對手發現他的移動(findMove)
  • 對手鎖定互斥鎖(pthread_mutex_lock)
  • 對手開始等待(調用pthread_cond_wait)
  • 主要功能鎖定互斥(的pthread_mutex_lock)
  • 球員他的行動
  • 主線程的信號,這是對手轉(pthread_cond_signal會)

然後,沒有任何反應。

我希望發生的事情(與互斥被鎖定在適當的地方)什麼:

  • 對手發現他的舉動(findMove)
  • 對手開始等待(調用pthread_cond_wait)
  • 播放器品牌他的舉動
  • 主線程的信號,這是對手轉(pthread_cond_signal會)
  • 對手停止等待
  • 對手使得動它以前想着
  • 對手切換當前播放器(setCurrentPlayer)
  • 重複

我並不是真的線程經歷過,所以可能會有人幫我出什麼在這裏,我怎麼可能修復它?我不知道是否在正確的位置有互斥鎖定/解鎖,條件信號/等待和setCurrentPlayer功能。

+2

在關鍵部分和條件調用周圍放置了一些日誌語句 - 您可以看到死鎖是如何產生的。猜測,我會說'getCurrentPlayer()'的值沒有正確更新... – Nim

+0

嘗試使用錯誤檢查互斥鎖。請參見['pthread_mutexattr_settype']上的'PTHREAD_MUTEX_ERRORCHECK'(http://pubs.opengroup.org/onlinepubs/007904875/functions/pthread_mutexattr_gettype.html)。 –

+0

我相當確定更新後的代碼應該可以工作。你能告訴我們'getCurrentPlayer()','setCurrentPlayer()'和初始化它們訪問的值的代碼嗎? –

回答

2

當您撥打pthread_cond_wait時,應該鎖定互斥鎖 - 該功能在返回之前以原子方式解鎖互斥鎖,等待信號並重新鎖定互斥鎖。互斥鎖的目的是串行訪問共享狀態(在本例中爲當前播放器),所以它應該鎖定在任何訪問權限周圍。循環應該更像:

while(!isGameOver()) { 
    if(!isValid(move)) { 
     move = findMove(); 
    } 

    pthread_mutex_lock(&mutex); // LOCK HERE 
    if(getCurrentPlayer() != OPPONENT) { 
     pthread_cond_wait(&cond, &mutex); 
    } 

    if(getCurrentPlayer() == OPPONENT) { 
     if(isValid(move)) { 
      // NOT HERE pthread_mutex_lock(&mutex); 

      // ... update board with opponent's move ... 

      setCurrentPlayer(PLAYER); 

      pthread_cond_signal(&cond); 
      // NOT HERE pthread_mutex_unlock(&mutex); 
     } 
    } 
    pthread_mutex_unlock(&mutex); // UNLOCK HERE 
} 

對於其他線程也是類似的。

+0

感謝您的幫助,但它似乎仍然沒有工作。我已經使用新代碼更新了原始帖子,以及它現在正在做什麼。 – shadow

+0

@shadow:你把鎖正好放在我的位置嗎? [此代碼](http://ideone.com/CZhtJ)適用於我。 –

+1

if(getCurrentPlayer()!= OPPONENT)應該是'while',以避免虛假的喚醒。 –

1

你應該鎖定互斥等待前解鎖等待的信號後,像這樣:

//... 
    while(!isGameOver()) { 
     pthread_mutex_lock(&mutex); 
     if(getCurrentPlayer() != PLAYER) { 
      pthread_cond_wait(&cond, &mutex); 
     } 
     pthread_mutex_unlock(&mutex); 
    // ... 

參見這裏:https://computing.llnl.gov/tutorials/pthreads/

他們有很容易理解的例子在那裏。

+0

我很確定互斥鎖/解鎖應該在while循環之外。 –

0

另一個注意事項:在調用 之前,您應該先運行這兩行。不能保證您的線程將在這兩行之前執行。

pthread_mutex_init(&mutex, NULL); 
pthread_cond_init(&cond, NULL);