1

Trying to solve philosophers dinning problem by creating a doorman to only allow 4 philosophers to dine at once, planned on using semaphores for this but there is limited material about them on the web, and i cant figure out how to increment to value of the semaphore once it has been signaled.

#define INITIAL_COUNT 1 
#define MAX_COUNT 4

main()

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

waiting()

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
    You are mixing windows WinAPI threading libary functions with c++ standard threading library. Choose something from the standard: http://en.cppreference.com/w/cpp/thread – marcinj Apr 20 '16 at 14:11

1 Answers1

1

Dining Philosophers Rebooted is a thorough treatment of this classic problem using modern C++ with std::thread and std::mutex. Full source code is available at the link.

This code works by representing each fork as a std::mutex. Then the trick is how to lock two mutexes simultaneously without causing deadlock. C++11/14 comes with a function expressly for this purpose:

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

The above paper explores several possible implementations of std::lock for the 2 mutex and 3 mutex cases, and identifies one algorithm that is never any worse than any other algorithm (and often much better).

The optimal implementation (according to this paper) is in fact the algorithm used by libc++.

Here is the Philosopher::eat() function for the "2-D" case in the paper:

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

For demonstration purposes only, the Philosopher randomly selects which fork to hold in the left and right hands. This randomness isn't required to solve the problem. The function could have been simplified to the following and still be correct:

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

In real code the call to ::lock should be std::lock, but this code is trying out several implementations of std::lock without invasively changing the std::lib.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577