многопоточность — Как увеличить значение семафора в C ++, чтобы решить философии Dinning

Пытаясь решить проблему с философами, создавая швейцара, позволяющего обедать только 4 философам, планируется использовать семафоры для этого, но в Интернете имеется ограниченный материал о них, и я не могу понять, как увеличить значение семафора как только это было сигнализировано.

#define INITIAL_COUNT 1
#define MAX_COUNT 4

главный()

philo.doorSemaphore = CreateSemaphore(
NULL,           //default security attributes
INITIAL_COUNT,  //initial count
MAX_COUNT,  //maximum count

NULL);

while (philo.not_dead == true)
{
int num_philosophers = 5;
for (int i = 0; i < 5; i++)
{
philo.mythread[i] =  thread (philosophersFunction, i);      //init 5 threads calling philofunction each loop
philo.mythread[i].join();                                   //join thread to current thread each loop
}
sleep_for(milliseconds(500));
system("cls");
}

ожидания ()

void Philosophers::waiting(int current)
{

dWaitResult = WaitForSingleObject(doorSemaphore, 0L);
//waitResult = WaitForSingleObject(semaphores, 0L);

switch (dWaitResult)
{
case WAIT_OBJECT_0:
p[current] = hungry;
ReleaseSemaphore(doorSemaphore, 1, NULL);
break;
case WAIT_TIMEOUT:
hunger[current] ++;
counter[current] ++;
case WAIT_FAILED :
break;

CloseHandle(doorSemaphore);
}
}

1

Решение

Обеденные философы перезагрузились это тщательное лечение этой классической проблемы с использованием современного C ++ с std::thread а также std::mutex, Полный исходный код доступен по ссылке.

Этот код работает, представляя каждый форк как std::mutex, Тогда дело в том, как заблокировать два мьютекса одновременно, не вызывая тупиковую ситуацию. C ++ 11/14 поставляется с функцией специально для этой цели:

template <class L1, class L2, class... L3>
void lock(L1&, L2&, L3&...);

Вышеупомянутый документ исследует несколько возможных реализаций std::lock для случаев с 2 мьютексами и 3 мьютексами и определяет один алгоритм, который никогда не бывает хуже любого другого алгоритма (и часто намного лучше).

Оптимальная реализация (согласно этой статье) — это алгоритм, используемый Libc ++.

Здесь Philosopher::eat() Функция для «2-D» случая в статье:

void
Philosopher::eat()
{
using Lock = std::unique_lock<std::mutex>;
Lock first;
Lock second;
if (flip_coin())
{
first = Lock(left_fork_, std::defer_lock);
second = Lock(right_fork_, std::defer_lock);
}
else
{
first = Lock(right_fork_, std::defer_lock);
second = Lock(left_fork_, std::defer_lock);
}
auto d = get_eat_duration();
::lock(first, second);
auto end = std::chrono::steady_clock::now() + d;
while (std::chrono::steady_clock::now() < end)
;
eat_time_ += d;
}

Только для демонстрационных целей Philosopher случайным образом выбирает, какую вилку держать в левой и правой руках. Эта случайность не требуется для решения проблемы. Функцию можно было бы упростить до следующего и все же быть правильной:

void
Philosopher::eat()
{
using Lock = std::unique_lock<std::mutex>;
Lock first { left_fork_, std::defer_lock};
Lock second{right_fork_, std::defer_lock};
auto d = get_eat_duration();
::lock(first, second);
auto end = std::chrono::steady_clock::now() + d;
while (std::chrono::steady_clock::now() < end)
;
eat_time_ += d;
}

В реальном коде вызов ::lock должно быть std::lock, но этот код пробует несколько реализаций std::lock без инвазивного изменения std :: lib.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]