bfd Subj : Re: std::msync To : comp.programming.threads From : Alexander Terekhov Date : Fri Feb 18 2005 01:36 pm < Forward Inline > -------- Original Message -------- Message-ID: <42150F0C.DD34B6A6@web.de> Date: Thu, 17 Feb 2005 22:39:24 +0100 From: Alexander Terekhov Newsgroups: comp.std.c++ Subject: Re: C++ multithreading model References: ... Ben Hutchings wrote: [...] > The PowerPC architecture at least doesn't have CAS; it has two > separate instructions for load-and-watch and store-if-not-modified (I > forget what they are actually called). Load-reserved and store-conditional. // doesn't provide "POSIX-safety" with respect to destruction class mutex_for_XBOX_NEXT { // noncopyable atomic m_lock_status; // 0: free, 1/-1: locked/contention auto_reset_event m_retry_event; // prohibitively slow bin.sema/gate template int attempt_update(int old, int new, T msync) { while (!m_lock_status.store_conditional(new, msync)) { ***** On assembly level (in MP-safe mode), acquire is implemented using trailing isync and release is implemented using leading sync/lwsync instructions. ***** int fresh = m_lock_status.load_reserved(msync::none); if (fresh != old) return fresh; } return old; } public: // ctor/dtor [w/o lazy event init] bool trylock() throw() { return !(m_lock_status.load_reserved(msync::none) || attempt_update(0, 1, msync::acq)); } // bool timedlock() omitted for brevity void lock() throw() { int old = m_lock_status.load_reserved(msync::none); if (old || old = attempt_update(0, 1, msync::acq)) { do { while (old < 0 || old = attempt_update(1, -1, msync::acq)) { ***** Acq above is needed in order to ensure proper ordering with respect to "semaphore lock" operation on m_retry_event below. Lock status transition 1 -> -1 must complete before "semaphore lock" operation will take place (otherwise a "deadlock" can arise). ***** m_retry_event.wait(); old = m_lock_status.load_reserved(msync::none); ***** Here proper ordering is ensured by semaphore lock operation (m_retry_event.wait()) which is meant to provide acquire semantics (m_lock_status.load_reserved(msync::none) must complete after semaphore lock operation). ***** if (!old) break; } } while (old = attempt_update(0, -1, msync::acq)); } } void unlock() throw() { if (m_lock_status.load_reserved(msync::none) < 0 || attempt_update(1, 0, msync::rel) < 0) { // or just !SC m_lock_status.store(0, msync::rel); m_retry_event.set(); ***** Ordering here is also important. m_retry_event.set() (semaphore unlock operation) is meant to provide release semantics (m_lock_status.store(0, msync::rel) must complete before semaphore unlock operation). ***** } } }; regards, alexander. . 0