Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #68408
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Newsgroups | comp.lang.c++ |
| Subject | Re: std::thread - DESPERATE NEED HELP!!! |
| Date | 2019-09-13 23:01 -0700 |
| Organization | Aioe.org NNTP Server |
| Message-ID | <qlhvnv$q4n$1@gioia.aioe.org> (permalink) |
| References | <NRaeF.332144$R83.166244@fx23.am4> <2hZeF.171439$423.71319@fx07.iad> <qlhsjd$d5m$1@gioia.aioe.org> <qlht56$fii$1@gioia.aioe.org> |
On 9/13/2019 10:17 PM, Chris M. Thomasson wrote:
> On 9/13/2019 10:07 PM, Chris M. Thomasson wrote:
>> On 9/13/2019 8:38 PM, Pavel wrote:
> [...]
>>> Sub-Note: sometimes (but I think, not in your case) it is correct to
>>> wait for signal not in a loop --
>>
>> Using condition variables directly? If the code thinks that the return
>> from a condvar wait means a signal was actually sent, well, this is
>> mistaken. However, there is something called the eventcount, that can
>> abuse a condvar wait. The predicate is atomic.
>
> The loop is different in an eventcount, iirc its something like:
>
> imagine trying to pop from any lock-free collection, and you want to
> make it wait on an empty condition, well:
>
> // quick pseudo-code
> ____________________________________________
> eventcount ec;
>
> node* n = null;
>
> // FAST PATH
> while ((n = try_pop()) == null)
> {
> // SLOW PATH
> eventcount_key eckey = ec.begin();
>
> if ((n = try_pop()) != null)
> {
> ec.leave(eckey);
> break;
> }
>
> // wait for it!
> ec.wait(eckey);
> }
>
> // n is an actual node we just popped! nice. :^)
> ____________________________________________
>
> The double check for the predicate is required here. An eventcount is
> like a condition variable for lock-free algorithms.
Wrt the use case above, here is a crude eventcount (called waitset)
implementation that uses Relacy Race Detector, but its easy to turn into
pure C++11. I put the standalone membars in some macros, sorry for that!
#define mb_relaxed std::memory_order_relaxed
#define mb_consume std::memory_order_consume
#define mb_acquire std::memory_order_acquire
#define mb_release std::memory_order_release
#define mb_acq_rel std::memory_order_acq_rel
#define mb_seq_cst std::memory_order_seq_cst
#define mb_relaxed_fence() std::atomic_thread_fence(mb_relaxed)
#define mb_consume_fence() std::atomic_thread_fence(mb_consume)
#define mb_acquire_fence() std::atomic_thread_fence(mb_acquire)
#define mb_release_fence() std::atomic_thread_fence(mb_release)
#define mb_acq_rel_fence() std::atomic_thread_fence(mb_acq_rel)
#define mb_seq_cst_fence() std::atomic_thread_fence(mb_seq_cst)
class waitset
{
std::mutex m_mutex;
std::condition_variable m_cond;
std::atomic<bool> m_waitbit;
VAR_T(unsigned) m_waiters;
public:
waitset()
: m_waitbit(false),
m_waiters(0)
{
}
~waitset()
{
bool waitbit = m_waitbit.load(mb_relaxed);
unsigned waiters = VAR(m_waiters);
RL_ASSERT(! waitbit && ! waiters);
}
private:
void prv_signal(bool waitbit, bool broadcast)
{
if (! waitbit) return;
m_mutex.lock($);
unsigned waiters = VAR(m_waiters);
if (waiters < 2 || broadcast)
{
m_waitbit.store(false, mb_relaxed);
}
m_mutex.unlock($);
if (waiters)
{
if (! broadcast)
{
m_cond.notify_one($);
}
else
{
m_cond.notify_all($);
}
}
}
public:
unsigned wait_begin()
{
m_mutex.lock($);
m_waitbit.store(true, mb_relaxed);
mb_seq_cst_fence();
return 0;
}
bool wait_try_begin(unsigned& key)
{
if (! m_mutex.try_lock($)) return false;
m_waitbit.store(true, mb_relaxed);
mb_seq_cst_fence();
return true;
}
void wait_cancel(unsigned key)
{
unsigned waiters = VAR(m_waiters);
if (! waiters)
{
m_waitbit.store(false, mb_relaxed);
}
m_mutex.unlock($);
}
void wait_commit(unsigned key)
{
++VAR(m_waiters);
m_cond.wait(m_mutex, $);
if (! --VAR(m_waiters))
{
m_waitbit.store(false, mb_relaxed);
}
m_mutex.unlock($);
}
public:
void signal()
{
mb_seq_cst_fence();
bool waitbit = m_waitbit.load(std::memory_order_relaxed);
prv_signal(waitbit, false);
}
void broadcast()
{
mb_seq_cst_fence();
bool waitbit = m_waitbit.load(std::memory_order_relaxed);
prv_signal(waitbit, true);
}
};
Back to comp.lang.c++ | Previous | Next — Previous in thread | Find similar | Unroll thread
std::thread - DESPERATE NEED HELP!!! Szyk Cech <szykcech@spoko.pl> - 2019-09-11 20:16 +0200
Re: std::thread - DESPERATE NEED HELP!!! "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-09-11 23:01 -0700
Re: std::thread - DESPERATE NEED HELP!!! Ralf Fassel <ralfixx@gmx.de> - 2019-09-12 11:14 +0200
Re: std::thread - DESPERATE NEED HELP!!! "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-09-13 12:53 -0700
Re: std::thread - DESPERATE NEED HELP!!! Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-13 23:38 -0400
Re: std::thread - DESPERATE NEED HELP!!! "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-09-13 22:07 -0700
Re: std::thread - DESPERATE NEED HELP!!! "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-09-13 22:17 -0700
Re: std::thread - DESPERATE NEED HELP!!! "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-09-13 23:01 -0700
csiph-web