Subj : Re: std::msync To : comp.programming.threads From : Alexander Terekhov Date : Fri Apr 01 2005 01:35 pm Message-ID: Subject: Re: refcounting mutable objects, hopefully the last time > Hm. The problem is that I want to rely on libstdc++'s "portable" > primitives and not define my own for every platform. So I can only > use their __atomic_add, __exchange_and_add, _GLIBCXX_READ_MEM_BARRIER > and _GLIBCXX_WRITE_MEM_BARRIER. Only-read and only-write stuff are not sufficient in the general case (apart from the fact that bidirectional fencing is really bad idea) for acquire/release protocol. In more recent GLIBC they do have "full" acquire/release stuff. Internally (IIRC ppc port or something), I mean. > I've tried to google these things but memory synchronization > seems totally unpenetrable. I wonder if someone besides you > understands your ddhlb and naked_competing notation. Yeah. Well, msync::ddhlb label is known to the Linux folk as read_barrier_depends() macro. Their notations sucks, because it IS a "label", not a bidirectional "disjoint" fence. As for naked_competing... in the past, I had "msync::none" for both "naked_competing" stuff and "naked_noncompeting" accesses. It occurred to me that it's probably better to distinguish them. Just an illustration, not real code: // Introspection (for bool argument below) aside for a moment template class mutex_and_condvar_free_single_producer_single_consumer { typedef isolated< aligned_storage< T > > ELEM; size_t m_size; // > 1 ELEM * m_elem; atomic< ELEM * > m_head; atomic< ELEM * > m_tail; ELEM * advance(ELEM * elem) const { return (++elem < m_elem + m_size) ? elem : m_elem; } ... public: ... void producer(const T & value) { ELEM * tail = m_tail.load(msync::naked_noncompeting); ELEM * next = advance(tail); while (next == m_head.load(msync::cchsb)) usleep(1000); new(tail) T(value); m_tail.store(next, msync::ssb); } T consumer() { ELEM * head = m_head.load(msync::naked_noncompeting); while (head == m_tail.load(type_list< msync::cchlb_t, msync::ccacq_t>:: element::type())) usleep(1000); T value(*head); head->~T(); m_head.store(advance(head), type_list< msync::slb_t, msync::rel_t >:: element::type()); return value; } }; The idea is to make it easier for compiler to reuse cached value and omit load instruction (in the example above) for msync::naked_noncompeting accesses if implementation does caching (more precise annotations helping to understand the stuff aside for a moment). regards, alexander. .