pthread_cond_wait странное поведение
Я пытаюсь решить проблему столовых философов с помощью C++.
Код скомпилирован с g++ -lpthread
,
Все решение на философах GitHub. Репозиторий содержит два файла cpp: main.cpp и philopher.cpp. "Main.cpp" создает переменную мьютекса, семафор, 5 условных переменных, 5 вилок и запускает философов. Семафор используется только для синхронизации старта философов. Другие параметры передаются философам для решения проблемы. "Philosopher.cpp" содержит решение для данной проблемы, но после нескольких шагов возникает тупик.
Тупик возникает, когда философ 0 ест, а философ 1 (рядом с ним) хочет взять вилки. Затем философ 1 взял мьютекс и не вернет его, пока философ 0 не опустит свои вилки. Философ 0 не может опустить свои вилки из-за взятого мьютекса, поэтому мы зашли в тупик. Проблема в методе Philosopher::take_fork, вызов pthread_cond_wait(a,b) не освобождает мьютекс b. Не можете понять, почему?
// Taking fork. If eather lef or right fork is taken, wait.
void Philosopher::take_fork(){
pthread_mutex_lock(&mon);
std::cout << "Philosopher " << id << " is waiting on forks" << std::endl;
while(!fork[id] || !fork[(id + 1)%N])
pthread_cond_wait(cond + id, &mon);
fork[id] = fork[(id + 1)%N] = false;
std::cout << "Philosopher " << id << " is eating" << std::endl;
pthread_mutex_unlock(&mon);
}
Пожалуйста, обратитесь к этому коду для отдыха.
1 ответ
Ваш звонок в pthread_cond_wait()
Это нормально, поэтому проблема должна быть в другом месте. У меня есть три ошибки, которые я вижу:
Во-первых, в main()
Вы только инициализируете первую переменную условия в массиве. Вам нужно инициализировать все N
переменные условия:
for(int i = 0; i < N; i++) {
fork[i] = true;
pthread_cond_init(&cond[i], NULL);
}
pthread_mutex_init(&mon, NULL);
Во-вторых, в put_fork()
у вас есть неправильный расчет для одной из переменных условия, чтобы сигнализировать:
pthread_cond_signal(cond + (id-1)%N); /* incorrect */
когда id
равен нулю, (id - 1) % N
равно -1, так что это будет пытаться сигнализировать cond - 1
, который не указывает на переменную условия (возможно, этот указатель фактически повреждает ваш мьютекс, так как он может быть помещен непосредственно перед cond
в стеке). Расчет, который вы на самом деле хотите:
pthread_cond_signal(cond + (id + N - 1) % N);
Третий баг не является причиной вашего тупика, но вы не должны звонить srand(time(NULL))
каждый раз, когда вы звоните rand()
- просто позвоните один раз, в начале main()
,