@keeper_of_the_comp

Что делает в данной ситуации yield()?

данный код - реализация задачи обедающие философы

что в данном случае в функции lock_smart_politeделает yield() и почему когда мы пытаемся разлочить правую вилку без yield() не получается

#include <iostream>
#include <iomanip>
#include <string>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>

size_t eat_sleep_interval = 100;
size_t think_sleep_interval = 10;
size_t max_eat_times = 10;
using namespace std;
void message(const int x, const std::string& message)
{
    std::cout << std::setfill('0') << std::setw(2) << x << message << std::endl;
}

void sleep(int millisec)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(millisec));
}

template <class L0, class L1>
void lock_naive(int x, L0& left, L1& right)
{
    message(x, " will take left fork");
    left.lock();
    message(x, " will take right fork");
    right.lock();
    message(x, " will eat...");
    sleep(eat_sleep_interval);

    message(x, " will put left fork");
    right.unlock();
    message(x, " will put right fork");
    left.unlock();
}

template <class L0, class L1>
void lock_smart_polite(int x, L0& left, L1& right)
{
    while (true)
    {
        {
            std::unique _lock<L0> left_lock(left);
            message(x, " taken left fork...");
            if (right.try_lock())
            {
                message(x, " taken right fork...");
                sleep(eat_sleep_interval);
                message(x, " finished eating...");
                left_lock.release();
                message(x, " put back both forks");
                break;
            }
            else {
                message(x, " failed to take right fork, put left back");
             //   left_lock.release();
            }
        }//
        std::this_thread::yield();

        {
            std::unique_lock<L1> right_lock(right);
            message(x, " taken right fork...");
            if (left.try_lock())
            {
                message(x, " taken left fork...");
                sleep(eat_sleep_interval);
                message(x, " finished eating...");
                right_lock.release();
                message(x, " put back both forks");
                break;
            }
            else {
                message(x, " failed to take left fork, put right back");
            }
        }
        std::this_thread::yield();
    }
}

void philosopher(int x, std::mutex& left, std::mutex& right)
{
    for (int times = 0; times < max_eat_times; times++)
    {
        lock_smart_polite(x, left, right);
        left.unlock();
        right.unlock();
        message(x, " will think...");
        sleep(think_sleep_interval);
    }
}

int main(int argc, char* argv[])
{
    size_t phil_num = 5;

    if (argc > 1)
        phil_num = std::stoi(argv[1]);

    std::cout << "Will work with " << phil_num << " philosophers" << std::endl;

    std::vector<std::mutex> forks(phil_num);

    std::thread* phils = new std::thread[phil_num];
    for (int i = 0; i < phil_num; i++)
        phils[i] = std::thread(philosopher, i, std::ref(forks[i]), std::ref(forks[(i + 1) % phil_num]));

    for (int i = 0; i < phil_num; i++)
        phils[i].join();

    delete[] phils;

    return 0;
}
  • Вопрос задан
  • 1391 просмотр
Пригласить эксперта
Ответы на вопрос 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Читайте документацию.

Yield говорит планировщику, что сейчас хорошо бы текущий поток вытеснить.

Зачем он тут нужен? В сильно конкурентной среде это позволит другим потокам что-то доделать и сократить накладные расходы на попытки захватить мьютекс. Но вообще говоря тут он не нужен. И вообще надеяться на yield - плохая идея. Планировщик может его и вообще проигнорировать.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы