I'm getting an error every time I try waiting on my condition_variable when compiling in Xcode. Error is "terminating with uncaught exception of type std::__1::system_error: condition_variable wait failed: Invalid argument"
Everything works fine in Visual Studio 2013. Code works if I decide to not wait on the same condition_variable from multiple threads. Grrrr.
Ok, code.
main.cpp:
#include "ThreadPool.h"
int main(int argc, const char * argv[])
{
ThreadPool pool;
for (int i = 0; i < 10; ++i)
pool.sendWork();
std::this_thread::sleep_for(std::chrono::milliseconds(50000));
return 0;
}
ThreadPool.h
#pragma once
#include <condition_variable>
#include <vector>
#include <thread>
class ThreadPool
{
protected:
std::condition_variable _condition;
private:
std::vector<std::thread> _threads;
void threadLoop();
public:
ThreadPool();
void sendWork();
};
ThreadPool.cpp:
#include "ThreadPool.h"
ThreadPool::ThreadPool()
{
for (unsigned int i {0}; i < 10; ++i)
_threads.push_back(std::thread(&ThreadPool::threadLoop, this));
}
void ThreadPool::threadLoop()
{
std::mutex mutex;
std::unique_lock<std::mutex> lock {mutex};
_condition.wait(lock); // This is where the crash happens
}
void ThreadPool::sendWork()
{
_condition.notify_one();
}
This is a major simplification of the real code, but it's enough to trigger the crash.
Is this supposed to work? Am I missing something here?
To be more precise, the Requires section of the spec of condition_variable::wait()
is (N3936 §30.5.1 [thread.condition.condvar]/p9):
void wait(unique_lock<mutex>& lock);
Requires:
lock.owns_lock()
istrue
andlock.mutex()
is locked by the calling thread, and either— no other thread is waiting on this
condition_variable
object or—
lock.mutex()
returns the same value for each of the lock arguments supplied by all concurrently waiting (viawait
,wait_for
, orwait_until
) threads.
Thus, every thread concurrently waiting on a condition_variable
must pass in the same mutex. It is technically allowed for two threads to wait on a condition_variable
using one mutex, and then after both wait terminates (and no thread is waiting on the condition_variable
), for them to both wait on the same object using a different mutex. I do not know whether there are any realistic use cases for this.
Note also that std::condition_variable_any::wait()
does not have such a requirement. The only requirement on the type supplied is that it meets BasicLockable
requirements, which basically means that it has lock()
and unlock()
.
Your mutex in ThreadPool::threadLoop
is a local variable. That means that different threads are locking on different mutexes. This is invalid: condition variables are tied to a specific mutex and you must acquire a lock for that mutex before waiting on the condition.
You should declare a _mutex
(or, even better, use the mutex_
naming convention: underscore-prefix identifiers are mostly reserved) member variable in your ThreadPool
class, and always lock on that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With