c++ - 如何在 C++ 中增加信号量值,解决哲学家用餐问题

标签 c++ multithreading mutex semaphore dining-philosopher

试图通过创建一个只允许 4 位哲学家同时用餐的门卫来解决哲学家就餐问题,计划为此使用信号量,但网络上关于它们的资料有限,我无法弄清楚如何增加值(value)信号量一旦发出信号。

#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);
    }
}

最佳答案

Dining Philosophers Rebooted是使用带有 std::threadstd::mutex 的现代 C++ 彻底解决这个经典问题。链接中提供了完整的源代码。

此代码通过将每个 fork 表示为 std::mutex 来工作。那么技巧就是如何在不引起死锁的情况下同时锁定两个互斥量。 C++11/14 带有一个专门用于此目的的函数:

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

上述论文针对 2 个互斥锁和 3 个互斥锁的情况探讨了 std::lock 的几种可能实现,并确定了一种算法,它永远不会比任何其他算法差(而且通常好得多) .

最佳实现(根据本文)实际上是 libc++ 使用的算法.

这是论文中“2-D”案例的 Philosopher::eat() 函数:

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;
}

仅出于演示目的,哲学家 随机选择左手和右手握住哪个 fork 。解决问题不需要这种随机性。该函数可以简化为以下内容并且仍然正确:

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。

关于c++ - 如何在 C++ 中增加信号量值,解决哲学家用餐问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36746454/

相关文章:

linux - 什么是非阻塞信号量?

c++ - 用 wxWidgets 绘图

c++ - 进一步优化DP解决方案的提示

Java 同步和集合

c++ - Linux 套接字和线程

c++ - 如果互斥量由成员管理,您是否需要类/结构的互斥量?

c++ - 使用指针时无限循环

c++ - 开源 C++ 程序,接收 GPS (NMEA) 语句或 x,y 坐标并在 map 上播放位置

python - 可以同时对 SQLite 数据库进行多个读/写操作吗?

c++ - 使用互斥锁和条件变量作为成员时如何修复 "use of deleted function"?