Granini
Granini

Reputation: 33

boost condition_variable wait for multiple locks

I have problems getting used to thread programming. I have tried to build a construct with mutex and locks. But I need boost::condition_variable::wait with two locks as parameter. But there is no wait function for two locks.

Does anyone have a tip for me, or is my approach totally wrong?

My aim is



    class Archive
    {
        vector externalBuffer;
        vector swapBuffer;
        vector internalBuffer;
        boost::mutex externalBufferMutex;
        boost::mutex allBufferMutex;
        boost::condition_variable bufferIsFilledConditionVariable;

        void operator () ()
        {
            unique_lock allBufferLock(allBufferMutex);
            while(true)
            {
                {
                    unique_lock lock(externalBufferMutex);
                    while(buffer.empty())
                    {
                        bufferIsFilledConditionVariable.wait(...); // I should call it with two locks?
                    }
                    externalBuffer.swap(swapBuffer);
                }

                {
                    internalBuffer.swap(swapBuffer);
                    // store values from internalBuffer
                    ...
                    internalBuffer.clear();
                }
            }
        }

        void add(value) // pseudo code here
        {
            {
                lock_guard lock(externalBufferMutex);
                externalBuffer.push_back(value);
            }
            bufferIsFilledConditionVariable.notify_one();
        }

        // search will not be used concurrently with add()
        // it should just wait for the worker thread
        someReturnValue search()
        {
            unique_lock lock(allBufferMutex);
            // search here
            ...
        }

    }

Upvotes: 2

Views: 902

Answers (2)

sehe
sehe

Reputation: 392979

I'm not sure what you are trying to achieve and in general, you should avoid operating under multiple, overlapping, locks.

However, also in general, to avoid deadlocks, you just use consistent lock ordering. The non-member lock functions can help with that:

Example

unique_lock lk_all(allBufferMutex,      boost::defer_lock);
unique_lock lk_ext(externalBufferMutex, boost::defer_lock);
boost::lock(lk_all, lk_ext);

while(internalBuffer.empty())
{
    lk_all.unlock();
    bufferIsFilledConditionVariable.wait(lk_ext);
    boost::lock(lk_all, lk_ext);
}

This is untested, but may help you on your way

Upvotes: 1

dewaffled
dewaffled

Reputation: 2973

You can manually call allBufferLock.unlock before wait and lock after. But be aware, nested locks of multiple mutexes can easily cause deadlock if at some other place they'll also be both locked. It would be much more safe to unlock one before acquiring the other, e.g. having internalBufferLock instead of allBufferLock if possible.

Upvotes: 0

Related Questions