2011-11-03 23 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);