Reputation: 33
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
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:
Locks the Lockable objects supplied as arguments in an unspecified and indeterminate order in a way that avoids deadlock. It is safe to call this function concurrently from multiple threads with the same mutexes (or other lockable objects) in different orders without risk of deadlock. If any of the lock() or try_lock() operations on the supplied Lockable objects throws an exception any locks acquired by the function will be released before the function exits.
http://en.cppreference.com/w/cpp/thread/lock (for c++11)
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
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