Блокировка доступа к структуре с помощью мьютекса - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть структура, содержащая два элемента.

struct MyStruct {
  int first_element_;
  std::string second_element_;
}

Структура распределяется между потоками и поэтому требует блокировки. Мой вариант использования требует блокировки доступа к структуре whole вместо просто определенного элемента c, например:

  // start of Thread 1's routine
  <Thread 1 "locks" struct>
  <Thread 1 gets first_element_>
  <Thread 1 sets second_elements_>
  <Thread 2 wants to access struct -> blocks>
  <Thread 1 sets first_element_>
  // end of Thread 1's routine
  <Thread 1 releases lock>
  <Thread 2 reads/sets ....>

Какой самый элегантный способ сделать это?

РЕДАКТИРОВАТЬ: Чтобы уточнить, в основном этот вопрос о том, как принудительно использовать любой поток, используя эту структуру для блокировки мьютекса (хранится где угодно) в начале своей процедуры и разблокировать мьютекс в конце его.

EDIT2: Мое текущее (безобразное) решение состоит в том, чтобы создать мьютекс внутри MyStruct и заблокировать этот мьютекс в начале процедуры каждого потока, которая использует MyStruct. Однако, если один поток «забывает» заблокировать этот мьютекс, у меня возникают проблемы с синхронизацией.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2020

Вы можете реализовать что-то вроде этого, объединяющее блокировку с данными:

class Wrapper
{
public:
   Wrapper(MyStruct& value, std::mutex& mutex)
   :value(value), lock(mutex) {}

   MyStruct& value;
private:
   std::unique_lock<std::mutex> lock;
};

class Container
{
public:
   Wrapper get()
   {
      return Wrapper(value, mutex);
    }
private:
   MyStruct value;
   std::mutex mutex;
};

Мьютекс блокируется при вызове get и автоматически разблокируется, когда Wrapper выходит из области видимости.

0 голосов
/ 05 февраля 2020

Вы можете иметь класс вместо struct и реализовать геттеры и сеттеры для first_element_ и second_element_. Помимо этих учеников, вам также понадобится член типа std::mutex.

В конечном итоге ваш класс может выглядеть следующим образом:

class Foo {
public:
    // ...

    int get_first() const noexcept {
        std::lock_guard<std::mutex> guard(my_mutex_);
        return first_element_;
    }

    std::string get_second() const noexcept {
        std::lock_guard<std::mutex> guard(my_mutex_);
        return second_element_;
    }

private:
    int first_element_;
    std::string second_element_;
    std::mutex my_mutex_;
};

Пожалуйста, примечание , что получатели возвращают копии членов данных. Если вы хотите вернуть ссылки (например, std::string const& get_second() const noexcept), вам нужно быть осторожным, потому что код, который получает ссылку на второй элемент, не имеет защиты блокировки, и в этом случае может быть условие гонки.

В любом случае, ваш путь к go использует std::lock_guard s и std::mutex es вокруг кода, который может использоваться более чем одним потоком.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...