Блокировка только одного из двух возможных мьютексов - PullRequest
0 голосов
/ 06 июня 2018

У меня есть многопоточная программа C ++, которая имитирует автомастерскую.По существу, car - это поток, а station - это ресурс.Он работает следующим образом: автомобиль входит в мастерскую, и у него есть список станций (только целые), которые он должен посетить, чтобы отремонтировать.Есть 3 типа станций:

  • 1x2 станция - 1 станция может ремонтировать 2 машины одновременно
  • 1x1 станция - 1 станция может ремонтировать 1 машину одновременно
  • 2x1 станция - есть две станции, необходимые для выполнения работы

Последние два типа были бы просты для меня, потому что в типе 1x1 я просто блокирую мьютекс на station и другиетемы должны ждать.На типе 2x1 я просто выбираю std::lock на двух станциях, чтобы избежать тупиковых ситуаций и т. Д.

Проблема с первым типом.Давайте представим, что ремонт двух вагонов одновременно означает, что один вагон находится с левой стороны станции, а другой с правой стороны (мне также придется нарисовать эту ситуацию с ncurses).Поэтому я подумал о реализации станции для типа 1x2 следующим образом:

class station1x2 {
public:
    std::mutex r_mutex;
    std::mutex l_mutex;
}

Поэтому я хотел бы заблокировать либо r_mutex, либо l_mutex, поэтому существует 4 возможных сценария:

  • оба они не заблокированы, я блокирую, какой из них
  • правый заблокирован, я блокирую левый
  • левый заблокирован, я блокирую правыйone
  • они оба заблокированы, я жду

Проблема здесь: есть ли в C ++ механизм для блокировки только одного из данных мьютексов?(как будто я даю некоторую функцию моим r_mutex и l_mutex, и он выбирает незафиксированный и блокирует его для меня).

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Мьютекс не является правильным примитивом синхронизации здесь.Это можно сделать с помощью семафора (в основном это примитив 0-n, где мьютекс равен 0-1), но в стандартной библиотеке нет семафора.

Существует условная переменнаяОднако, который вы можете использовать здесь.Вам понадобится:

  • Условная переменная для обозначения "есть свободное место на станции"
  • Счетчик (или другие средства, такие как два логических значения), представляющий свободные места на станции
  • Мьютекс для их защиты

При входе на станцию ​​заблокируйте мьютекс и посмотрите, есть ли свободное место.Если есть, займите один, отпустите мьютекс и получите ремонт.Если оба заполнены, подождите условную переменную (это освободит мьютекс).

По завершении ремонта заблокируйте мьютекс, отметьте свободное место, освободите мьютекс и уведомите переменную условия (так как естьсвободного места сейчас).

В коде:

class station1x2 {
public:
    std::mutex mutex;
    std::condition_variable cond;
    int freeSpaces;

    void enter() {
      std::unique_lock<std::mutex> l(mutex);
      cond.wait(l, [&]() { return freeSpaces > 0; }
      --freeSpaces;
    }

    void exit() {
      {
        std::unique_lock<std::mutex> l(mutex);
        ++freeSpaces;
      }
      cond.notify_one();
    }
}
0 голосов
/ 06 июня 2018

В вашем случае я бы использовал метод try_lock.Этот метод возвращает true (и блокирует мьютекс), если блокировка возможна, false в противном случае (уже заблокированный мьютекс).

if (!r_mutex.try_lock() && !l_mutex.try_lock())
  std::cout << "All mutexes already locked" << std::endl;
...