#c #boost #mutex
#c #повысить #мьютекс
Вопрос:
class MyClass
{
public:
void PushMessage(MyMessage m) // Thread 1 calls this
{
boost::mutex::scoped_lock lock(mMutex);
mQueue.push_back(m);
mCondition.notify_one();
}
MyMessage PopMessage()
{
boost::mutex::scoped_lock lock(mMutex);
while(mQueue.empty())
mCondition.wait(lock);
MyMessage message = mQueue.front();
mQueue.pop_front();
return message;
}
void foo() // thread 2 is running this loop, and supposed to get messages
{
for(;;)
{
MyMessage message = PopMessage();
do_something(message);
}
}
private:
std::deque<MyMessage> mQueue;
boost::mutex mMutex;
boost::condition mCondition;
};
Когда я запускаю код, PushMessage
вызывается и foo()
ожидает PopMessage()
, но PopMessage
никогда не возвращается.
То, что do_something
здесь не имеет значения, я думаю.
Что я здесь делаю не так? Как ни странно, приведенный выше код отлично работал под Mac, но у меня возникли проблемы с Linux.
версия boost — 1.44.0
Спасибо
Комментарии:
1. Что такое
do_something
? Кто вызываетPushMessage
? Этот код в лучшем случае неполный.2. В библиотеке потоков нет
boost::condition
. Ты имел в видуboost::condition_variable
? Как написано, и с этим исправлением, ваш код выполняется в Linux с boost 1.42 и boost 1.46 (у вас нет 1.44 под рукой) и не показывает проблем, которые вы описываете.
Ответ №1:
Вместо того, чтобы позволить области действия объекта блокировки истечь до его разблокировки, вы могли бы попытаться вручную разблокировать мьютекс в PushMessage()
, прежде чем разблокировать ожидающий поток, т.Е.,
void PushMessage(MyMessage m) // Thread 1 calls this
{
boost::mutex::scoped_lock lock(mMutex);
mQueue.push_back(m);
lock.unlock(); // <== manually unlock
mCondition.notify_one();
}
Таким образом, когда поток 2 разблокируется, не будет времени «перехода», когда поток 1 содержит блокировку, а поток 2 пытается получить блокировку вашего мьютекса. Я не понимаю, почему это создало бы проблемы, но опять же, по крайней мере, у вас не будет потока 2, пытающегося вызвать lock.lock()
, пока поток 1 все еще содержит блокировку.
Комментарии:
1. Недавно я узнал, что это на самом деле сложнее, чем кажется, вот ссылка: domaigne.com/blog/computing/… есть такая вещь, как
wait morphing
оптимизация, которая предотвращает проблему, о которой вы говорите. И уведомление во время блокировки сделает общую программу более безопасной при использовании более 2 потоков.
Ответ №2:
Я думаю, вам нужны 2 объекта мьютекса, один для синхронизации вызова метода в разных потоках, другой для ожидания условия. Вы их перепутали.
Комментарии:
1. Я не думаю, что это правильно. Мьютекс должен защищать как сигнал / ожидание, так и набор условий / проверку состояния. Условие в данном случае
mQueue.empty()
, таким образом, очередь должна быть защищена этим же мьютексом.