Weird problem with mutex and lock error
Hello,
I am getting a nasty error condition from a mutex where it calls
std::terminate. I hope someone here will be able to explain why. The
error message is:
terminate called after throwing an instance of
'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error>
' what(): boost::lock_error
I read somewhere that the fix for this is to use a recursive mutex. I
don't understand why a recursive mutex should be required in my case.
Here is my situation: I have a parent thread that owns an object that
contains a concurrent queue. This object is set up from info in a
config file. Let us call this object a config object. Under certain
conditions the parent thread re-reads the config file and recreates
the config object. The object is managed using a scoped_ptr so when I
need to blow the old object away I create a new config object then do
a reset to that object pointer. Here is the concurrent queue object
that the config object contains:
template<typename Data>
class concurrent_queue
{
private:
std::queue<Data> the_queue;
mutable boost::mutex the_mutex;
boost::condition_variable the_condition_variable;
public:
void push(Data const& data)
{
boost::mutex::scoped_lock lock(the_mutex);
the_queue.push(data);
lock.unlock();
the_condition_variable.notify_one();
}
bool empty() const
{
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.empty();
}
bool try_pop(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
if(the_queue.empty())
{
return false;
}
popped_value=the_queue.front();
the_queue.pop();
return true;
}
struct queue_not_empty
{
std::queue<Data>& queue;
queue_not_empty(std::queue<Data>& queue_):
queue(queue_)
{}
bool operator()() const
{
return !queue.empty();
}
};
void wait_and_pop(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
the_condition_variable.wait(lock, queue_not_empty(the_queue));
popped_value = the_queue.front();
the_queue.pop();
}
template<typename Duration>
bool timed_wait_and_pop(Data& popped_value, Duration const&
wait_duration)
{
bool got_value;
boost::mutex::scoped_lock lock(the_mutex);
if (the_condition_variable.timed_wait(lock, wait_duration,
queue_not_empty(the_queue)))
{
popped_value = the_queue.front();
the_queue.pop();
got_value = true;
}
else
{
got_value = false;
}
return got_value;
}
};
The queue is used for the parent thread to communicate with various
child threads that it spawns.
I managed to reproduce the error in the debugger and the exception is
thrown from concurrent_queue in the first line of the push method
(where it gets the lock).
I am not sure how this can be since the config object is only supposed
to be destroyed when there are no child threads left. It is as if a
child thread is still trying to write to the queue when the parent is
trying to destroy it.
If my suspicion is right then I don't think it would be right to
correct this error by changing the concurrent queue to use a recursive
mutex. What do people think?
This is a bif of a tricky issue because the parent cannot know that a
child will finish properly. The child threads do a fork and an exec
and it is possible that the exec will not return.
Regards,
Andrew Marlow
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]