Yes (I tested this in December 2012), and there is a solution I conjured up for this a while ago. The "Flare" class:
Note that it uses a spin lock, but the time spent in this is minimal.
Declaration (hpp):
class Flare
{
public:
/**
\brief Flare's constructor.
\param fall_through_first, will skip the first wait() if true.
*/
Flare(bool fall_through_first = false);
/**
\brief Flare's destructor.
Takes care of removing the object of this class.
*/
~Flare();
/**
\brief Notifies the same object of availability.
Any thread waiting on this object will be freed,
and if the thread was not waiting, it will skip
wait when it iterates over it.
*/
void notify();
/**
\brief Wait until the next notification.
If a notification was sent whilst not being
inside wait, then wait will simply be skipped.
*/
void wait();
private:
std::mutex m_mx; // Used in the unique_lock,
std::unique_lock<std::mutex> m_lk; // Used in the cnd_var
std::condition_variable m_cndvar;
std::mutex m_in_function, n_mx; // protection of re-iteration.
bool m_notifications;
};
Implementaton/Definition (cpp):
#include "Flare.hpp"
// PUBLIC:
Flare::Flare(bool fall_through_first)
:
m_lk(m_mx),
m_notifications(!fall_through_first)
{}
Flare::~Flare()
{}
void Flare::notify()
{
if (m_in_function.try_lock() == true)
{
m_notifications = false;
m_in_function.unlock();
}
else // Function is waiting.
{
n_mx.lock();
do
{
m_notifications = false;
m_cndvar.notify_one();
}
while (m_in_function.try_lock() == false);
n_mx.unlock();
m_in_function.unlock();
}
}
void Flare::wait()
{
m_in_function.lock();
while (m_notifications)
m_cndvar.wait(m_lk);
m_in_function.unlock();
n_mx.lock();
m_notifications = true;
n_mx.unlock();
}