увеличьте мьютекс, условие, scoped_lock, я использую их здесь неправильно?

#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() , таким образом, очередь должна быть защищена этим же мьютексом.