Последняя попытка действительно неверна, поскольку может случиться так, что несколько потоков вызовут down
одновременно, и все успешно пройдут
while (this->count == 0)
std::this_thread::yield();
строки, и тогда все они уменьшат счетчик до возможного отрицательного значения.значение:
this->mutualExclusion.lock();
this->count--;
this->mutualExclusion.unlock();
Таким образом, проверка и обновление значения счетчика должны выполняться атомарно.
Если вы хотите сохранить занятый цикл, самый простой способ - просто вызвать unlock
до выходаи lock
после, поэтому сравнение и уменьшение будут выполняться под одной и той же блокировкой:
void down() {
this->mutualExclusion.lock();
while (this->count == 0) {
this->mutualExclusion.unlock();
std::this_thread::yield();
this->mutualExclusion.lock();
}
this->count--;
this->mutualExclusion.unlock();
}
Также вы можете использовать std::unique_lock
guard, который блокирует мьютекс в конструкторе и разблокирует в деструкторе, поэтому мьютексне будет случайно оставлен в заблокированном состоянии:
void down() {
std::unique_lock<std::mutex> lock(this->mutualExclusion);
while (this->count == 0) {
lock.unlock();
std::this_thread::yield();
lock.lock();
}
this->count--;
}
Чтобы справиться с ошибкой "muxed уничтожен во время занятости", вам нужно либо иметь флаг, чтобы остановить фоновые потоки, и ждать, пока они завершатся с join
of detach:
#include <atomic>
...
std::atomic<bool> stopped{ false };
void philosopher(short i) {
while (!stopped) {
...
}
}
...
int main()
{
...
stopped = true;
for (int i = 0; i < N; i++) {
threadsVector[i]->join();
}
return 0;
}
или, если вы действительно не хотите заботиться об освобождении статических ресурсов, вы можете позвонить std :: quick_exit вместо detach
и return
:
int main()
{
...
std::this_thread::sleep_for(std::chrono::milliseconds(15000));
std::quick_exit(0);
}