Возможные причины того, что pthread_cond_wait () не освобождает мьютекс? - PullRequest
0 голосов
/ 03 августа 2011

У моей программы, похоже, проблема с тупиком.

В основном у меня есть класс, который выглядит так:

class Foo {
public:
  Foo();

  void bar();

private:
  void monitor();

  bool condition_;
  pthread_t monitor_;
  pthread_mutex_t mutex_;
  pthread_cond_t cv_;
};

В конструкторе Foo я вызываю monitor() в отдельном потоке (а именно monitor_). Эта monitor() функция выполняет следующие действия:

pthread_mutex_lock(&mutex_);
while (true) {
  while (!condition_) {
    pthread_cond_wait(&cv_, &mutex_);
  }
  // do something
  // and then setting condition_ to false
  condition_ = false;
}
pthread_mutex_unlock(&mutex_);

Функция bar() является единственным общедоступным интерфейсом (исключая ctor и dtor) из Foo. Также необходимо получить мьютекс в своем исполнении. Мой симптом в том, что bar() никогда не сможет приобрести mutex_. Похоже, что pthread_cond_wait() не освобождает мьютекс, как это должно быть. И если я отключу поток монитора (таким образом, не участвуя в гонках), тогда bar() сможет без проблем запустить его до конца.

Конечно, приведенный выше код является урезанной версией моего реального кода. На самом деле я думаю, что в этом коде нет логической ошибки, и я правильно использую pthread. Я подозреваю, есть ли другие причины для этой тупиковой ситуации. Кто-нибудь может дать подсказку по этому поводу? Спасибо!

Ответы [ 3 ]

0 голосов
/ 03 августа 2011

Я бы посмотрел на ваш конструктор и функцию bar () и, возможно, если вы случайно сделали копию рассматриваемого объекта.Я скопировал предоставленные вами классы и мои предположения о том, как все остальное работает ниже.Программа ниже просыпается каждую секунду, и сигнализирует поток.

#include <pthread.h>
#include <iostream>

class Foo {
public:
  Foo() {
    condition_ = false;
    pthread_mutex_init(&mutex_, NULL);
    pthread_cond_init(&cv_, NULL);
    pthread_create(&monitor_, NULL,
           startFunc, this);
  }

  void bar() {
    pthread_mutex_lock(&mutex_);
    std::cout << "BAR" << std::endl;
    condition_ = true;
    pthread_cond_signal(&cv_);
    pthread_mutex_unlock(&mutex_);
  }

private:
  Foo(const Foo&) {};
  Foo& operator=(const Foo&) { return *this; };

  static void* startFunc(void* r) {
    Foo* f = static_cast<Foo*>(r);
    f->monitor();
    return NULL;
  }

  void monitor() {
    pthread_mutex_lock(&mutex_);
    while (true) {
      while (!condition_) {
    pthread_cond_wait(&cv_, &mutex_);
      }
      // do something
      // and then setting condition_ to false
      std::cout << "FOO" << std::endl;
      condition_ = false;
    }
    pthread_mutex_unlock(&mutex_);

  }

  bool condition_;
  pthread_t monitor_;
  pthread_mutex_t mutex_;
  pthread_cond_t cv_;
};


int main() {
  struct timespec tm = {1,0};
  Foo f;

  while(true) {
    f.bar();
    nanosleep(&tm, NULL);
  }

}
0 голосов
/ 06 сентября 2013

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

Моя проблема заключалась в том, что я установил мьютекс как рекурсивный (с помощью settype-> PTHREAD_MUTEX_RECURSIVE_NP) и по ошибке дважды блокировал мьютекс перед вызовом cond_wait. Поскольку cond_wait разблокировал его только один раз, мьютекс все еще был заблокирован. Очевидным решением было заблокировать его только один раз. Кроме того, как показал урок, я не буду использовать рекурсивную настройку мьютекса, если в этом нет особой необходимости.

0 голосов
/ 03 августа 2011

Могу поспорить, что здесь не получится:

while (!condition_) {
    pthread_cond_wait(&cv_, &mutex_);
}

Предположим, условие ложно. Вы входите в цикл while и при первом запуске все идет хорошо, то есть вы разблокируете мьютекс и ждете переменную принятия решения. Может ли случиться так, что переменная условия изменится, но не логическое условие ? В этом случае вы должны ввести pthread_cond_wait с неинициализированным мьютексом, и может произойти неопределенное поведение ... Я думаю, это помогло бы, если бы вы также показали метод bar ().

Еще одно предположение - приоритеты потоков. Может быть, добавить выход, чтобы дать нитям больше шансов на переключение.

...