#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 ожидает, пока карта станет «действительной» (не пустой). Когда это допустимо, оно должно продолжать быть уверенным, что на карте что-то есть.