C : синхронизация потоков

#c #boost #synchronization #mutex #condition-variable

#c #повышение #синхронизация #мьютекс #условие-переменная

Вопрос:

Я пытаюсь синхронизировать два потока (работающих на одной карте C ), используя библиотеку Boost. Я должен сказать, что я не эксперт в C , и я нахожу документацию boost довольно сложной для понимания.

Чего я хочу достичь, это что-то вроде этого:

 #Thread 1
get access to the map
put in something
release access 

#Thread 2
wait until map is empty
when it's not empty anymore, wake up and gain access
perform operations on one entry of the map
leave access to somebody else
  

Я пытался использовать мьютекс и condition_variables, но код не работал должным образом. В частности, когда thread2 просыпался (после ожидания завершения. переменная), он не получал прямого доступа к карте, но был кто-то другой, кто получил доступ и очистил карту. Таким образом, я получил ошибку сегментации, потому что я ожидал, что карта будет заполнена, в то время как при обращении к ней она была пустой.

Кроме того, я хотел бы понять разницу между чем-то вроде mymutex.lock() и такими вызовами, как boost::mutex::scoped_lock scopedLock(mutex_) ; или unique_lock .

Спасибо за обучение 🙂

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

 //COMMON PART
boost::mutex mutex1;
boost::mutex mutex2;
boost::condition_variable cond;
boost::mutex::scoped_lock mutex2lock(mutex2);

//THREAD 1
...
if(someCondition){
    mutex1.lock();
    map[id]=message;
    cond.notify_one();
    mutex1.unlock();
}
...


//THREAD 2
...
cond.wait(mutex2lock);
mutex.lock();
//Perform operation on map[id]
doSomething(map[id]));
mutex.unlock();
...
  

Комментарии:

1. Вы должны добавить некоторый код о том, что делают фактические потоки. Сложно отлаживать, когда thread2 просыпался, он не получал прямого доступа к карте … Ваше описание, похоже, указывает на то, что существует один производитель и один потребитель, что не объясняет, что кто-то другой очистил карту . Существует ли только 2 потока? они действительно совместно используют карту?

2. да, они действительно совместно используют карту, которая является своего рода контейнером. Оба потока могут помещать / удалять данные. Иногда происходит то, что thread1 получает доступ два раза один за другим. В первый раз он что-то туда помещает. Тем временем thread2 просыпается, потому что он увидел уведомление. НО перед продолжением thread2 снова выполняется thread1, и на этот раз запись удаляется из карты. Извините за то, что так сумбурно объясняю, я надеюсь, что это достаточно ясно: P

3. Почему thread1 когда -либо убирает что-либо с карты?? Это просто напрашивается на неприятности. Кроме того, это то, что вам действительно следовало включить в пример кода.

4. Thread1 — это принимающая функция. Если я получаю сообщение, которого нет на карте, я вставляю его. Если я получаю сообщение, а оно уже есть на карте, я удаляю его с карты (куда-нибудь еще). В обобщении, чего я хочу добиться, так это того, что когда thread2 возобновляется после wait (), он действительно имеет эксклюзивный доступ к этой карте. Я должен быть уверен, что thread2 видит запись, которая была введена thread1. Надеюсь, я достаточно ясно выразился 🙂 Спасибо за чтение!

Ответ №1:

Кроме того, я хотел бы понять разницу между чем-то вроде mymutex.lock() и вызовами типа boost::mutex::scoped_lock scopedLock(mutex_); или unique_lock.

В Google есть «c RAII»:

С помощью mymutex.lock() вы «вручную» блокируете мьютекс. (И позже придется разблокировать его «вручную».)

scoped_lock — это вспомогательный класс, который выполняет блокировку — и автоматическую разблокировку в конце своей области — за вас.

Ответ №2:

 boost::mutex::scoped_lock mutex2lock(mutex2);
  

Это должно, если я правильно понимаю, привести к большой блокировке мьютекса 2, которая будет длиться всю длину вашего мьютекса.

Вероятно, вы хотите эту блокировку в контексте второго потока, но я не очень понимаю, почему condition_variable этого хочет.

На самом деле, кажется, что condition_variable сам по себе немного не подходит для того, что вы делаете, читая документацию:

Атомарный вызов lock.unlock() блокирует текущий поток. Поток разблокируется при уведомлении вызовом this-> notify_one() или this-> notify_all(), или ложным образом

Мне кажется, что это описание может просто разблокировать, когда почувствует, что может запуститься (вероятно, в зависимости от времени) Похоже, вам, вероятно, потребуется проверить, действителен ли список, и если нет, снова вызовите wait, если вы планируете использовать condition_variable .

Комментарии:

1. Спасибо за подсказку! Проблема в точности такая, как вы ее описали. Thread2 ожидает, пока карта станет «действительной» (не пустой). Когда это допустимо, оно должно продолжать быть уверенным, что на карте что-то есть.