Игра C ++: pthread_cond_signal не пробуждает поток оппонента - PullRequest
1 голос
/ 03 ноября 2011

Я делаю игру, в которой пользователь играет против компьютера. Компьютерный оппонент думает о своем следующем ходу, пока это ход игрока. Если игрок движется к месту, где планировал переместить компьютерный противник, компьютерный противник снова начинает поиск своего движения.

Вот схема основной функции и функции оппонента:

[ОБНОВЛЕНО]

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 в нужных местах.

Ответы [ 3 ]

2 голосов
/ 03 ноября 2011

Мьютекс должен быть заблокирован при вызове 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
}

и аналогично для другого потока.

1 голос
/ 04 ноября 2011

Еще одно замечание: вы должны были запустить эти две строки перед вызовом pthread_create(); Нет никакой гарантии, что ваш поток будет выполнен перед этими двумя строками.

pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
1 голос
/ 03 ноября 2011

Вы должны заблокировать мьютекс до сигнала ожидания и разблокировать его после ожидания, например:

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

См. Также здесь: https://computing.llnl.gov/tutorials/pthreads/

Там есть вполне понятные примеры.

...