C++ C++;游戏:pthread_cond_信号不';不要叫醒对手

C++ C++;游戏:pthread_cond_信号不';不要叫醒对手,c++,pthreads,mutex,wait,C++,Pthreads,Mutex,Wait,我在做一个游戏,让用户和电脑玩。当轮到玩家时,电脑对手会考虑下一步行动。如果玩家移动到计算机对手计划移动的位置,计算机对手将再次开始搜索其移动 以下是主要功能和对手功能的概述: [更新] pthread_mutex_t mutex; pthread_cond_t cond; int main() { // ... initialize game variables, args to pass to opponent ... pthread_t thread; pthr

我在做一个游戏,让用户和电脑玩。当轮到玩家时,电脑对手会考虑下一步行动。如果玩家移动到计算机对手计划移动的位置,计算机对手将再次开始搜索其移动

以下是主要功能和对手功能的概述:

[更新]

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\u mutex\u lock)
  • 对手开始等待(pthread_cond_wait)
  • 主函数锁定互斥锁(pthread\u mutex\u lock)
  • 球员开始行动
  • 主线程表示该轮到对手了(pthread_cond_signal)
然后,什么也没发生

我希望发生什么(将互斥锁锁定在适当的位置):

  • 对手找到了他的移动(findMove)
  • 对手开始等待(pthread_cond_wait)
  • 球员开始行动
  • 主线程表示该轮到对手了(pthread_cond_signal)
  • 对手停止等待
  • 对手做出了之前考虑过的动作
  • 对手切换当前玩家(setCurrentPlayer)
  • 重复

我对线程没有太多的经验,所以有人能帮我解决这里发生的事情吗,以及我如何修复它?我不知道我的互斥锁/解锁、条件信号/等待和setCurrentPlayer函数是否在正确的位置。

当调用
pthread\u cond\u 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
}
另一个线程也是如此。

您应该在等待之前锁定互斥锁,并在发出等待信号后解锁互斥锁,如下所示:

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


还有一个注意事项:在调用
pthread_create()之前,应该先运行这两行代码
不能保证线程会在这两行之前执行

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

在关键部分和条件调用周围放置一些日志语句-您可以看到死锁是如何产生的。我猜,
getCurrentPlayer()
的值没有正确更新……请尝试使用错误检查互斥体。请参阅上的
PTHREAD\u MUTEX\u ERRORCHECK
。我确信更新后的代码应该可以工作。你能给我们看一下
getCurrentPlayer()
setCurrentPlayer()
,以及初始化他们访问的值的代码吗?谢谢你的帮助,但它似乎仍然不起作用。我已经用新代码更新了原来的帖子,它现在似乎在做什么。@shadow:你把锁放在我放的地方了吗?对我有效。应该是
如果(getCurrentPlayer()!=对手)
中,以避免虚假唤醒。您是否确保将“当前玩家”初始化为
玩家
对手
?如果您的代码被初始化为任何其他值,它将挂起。@MaximYegorushkin:也许,但在这种情况下,它将再次进入睡眠状态。我非常确定互斥锁锁定/解锁应该在while循环之外。