Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #68408

Re: std::thread - DESPERATE NEED HELP!!!

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>

Show all headers | View raw


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


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