I'm encountering difficulties using std::condition_variable
with my custom spin mutex implementation. It seems that std::condition_variable
expects a std::mutex
to be associated with its lock, leading to compilation errors when attempting to use a different mutex implementation.
Here's a simplified version of my code where the compilation error occurs:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
class SpinMutex {
public:
void lock() {
// Implement spin lock logic here
}
void unlock() {
// Implement spin unlock logic here
}
private:
// Implement atomic flag or other spin lock mechanism here
};
SpinMutex mutex;
std::condition_variable cv;
bool ready = false;
void worker_thread() {
// Do some work...
std::this_thread::sleep_for(std::chrono::seconds(1));
// Attempting to lock a SpinMutex with std::lock_guard
// This line will throw a compilation error
std::unique_lock<SpinMutex> lock(mutex);
ready = true;
cv.notify_one();
}
int main() {
std::thread worker(worker_thread);
{
std::unique_lock<SpinMutex> lock(mutex);
cv.wait(lock, [] { return ready; });
}
worker.join();
return 0;
}
As shown, the use of std::unique_lock
with SpinMutex
throws a compilation error. It appears that std::condition_variable
is tightly coupled with std::mutex, making it incompatible with custom mutex implementations like a spin mutex.
I think I can use std::condition_variable_any
but my question is why the standard decided to go this way? Is it because of legacy purposes or because they implement a special optimization for std::mutex
. In other words, for a non-genius developer e.g. SpinMutex
above, can I guarantee that std::mutex
will outperform my own implementation in general?
I think I can use
std::condition_variable_any
Yes, correct.
but my question is why the standard decided to go this way?
The purpose of the synchronization API's in C++ is to provide a portable wrapper around OS synchronization API's. And the design of the C++ API was highly influenced by the Linux pthreads API.
So std::mutex
and std::condition_variable
are meant to be as thin wrappers as possible around the underlying OS API. In terms of pthreads, std::mutex
maps to pthread_mutex_t
. And std::condition_variable
maps to pthread_cond_t
.
And a pthread_cond_t
waits on a pthread_mutex_t
. But at the time it was realized that:
std::mutex
, andstd::mutex
.Thus std::condition_variable_any
was designed to meet the needs of those wanting to wait on a generalized mutex concept while not making those who don't need that generality pay for the feature.
Here is an early paper with the design rationale:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html#condition
What this paper calls cond_var
was eventually renamed to condition_variable
. And what this paper calls gen_cond_var
was eventually renamed to condition_variable_any
.
Also of note: this paper goes into detail about the difficulty of implementing gen_cond_var
. However a bug still existed in this paper's implementation. It was more difficult than even the authors realized at the time. However all major implementations of std::condition_variable_any
are bug free as of C++11 as far as I know.