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()istrueandlock.mutex()is locked by the calling thread, and either— no other thread is waiting on this
condition_variableobject 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