Два мьютекса с условной переменной для блокировки одного класса, потоков - PullRequest
0 голосов
/ 12 мая 2019

Я пытаюсь решить проблему философов столовой, используя алгоритм Чанди-Мисры. Более подробное объяснение здесь: https://en.wikipedia.org/wiki/Dining_philosophers_problem

Я использую один мьютекс для блокировки измененных переменных, а другой - с условной переменной для уведомления о свободном использовании форка.

Я не вижу причины, по которой все мои философы едят в одно и то же время - они вообще не ждут других вилок. Кажется, я неправильно использую мьютексы.

Философская нить:

void philosopher::dine() {
    while(!is_initialized); // here threads waits until all other philosophers are initialized                                                
    while(!is_stopped) {
        eat();
        think(); // here just sleeps for a few seconds
    }
}

Есть метод:

void philosopher::eat() {
    left_fork.request(index);
    right_fork.request(index);

    std::lock(right_fork.get_mutex(), left_fork.get_mutex());                
    std::lock_guard<std::mutex> l1( right_fork.get_mutex(), std::adopt_lock );    
    std::lock_guard<std::mutex> l2( left_fork.get_mutex(), std::adopt_lock );

    int num = distribution(mt);
    std::cout << "Philsopher " << index << " eats for " << num 
               << "seconds." << std::endl;
    sleep(num);
    right_fork.free();
    left_fork.free();
}

Как выглядит класс форка:

enum fork_state {
    CLEAN, DIRTY
};

class fork_t {
    int index;
    int owner_id;
    mutable std::mutex condition_m;
    std::mutex owner_m;
    std::condition_variable condition;

    public:
    fork_t(int _index,int _owner_id);
    fork_t(const fork_t &f);
    void request(int phil_req);
    void free();
    std::mutex &get_mutex() { return owner_m; }
    fork_t& operator=(fork_t const &f);
};

void fork_t::request(int phil_req) {

    while (owner_id != phil_req ) {

        std::unique_lock<std::mutex> l(condition_m);

        if(state == DIRTY) {
            std::lock_guard<std::mutex> lock(owner_m);            
            state = CLEAN;
            owner_id = phil_req;
        } else {
            while(state == CLEAN) {
               std::cout<<"Philosopher " << phil_req << " is waiting for"<< index <<std::endl;
                condition.wait(l);
            }
        }
    }
}

void fork_t::free() {
    state = DIRTY;
    condition.notify_one();
}

В начале все вилки выдаются философам с более низким id. Буду благодарен за любые советы.

...