Re: [GD-General] Totally Safe lock-free FIFO for arbitrary-sized items.
Brought to you by:
vexxed72
From: Andras B. <and...@gm...> - 2006-08-20 05:34:34
|
Jon, I very much appreciate all the explanation and sharing of the = implementation details! It is extremely helpful!! To answer your question, when I asked for a 64 bit FIFO, I was thinking = of = the fully generic FIFO's on 64bit systems, with unlimited queue length, = = and with multiple producer and consumer threads. In this case, all the = solutions that I've found used linked lists with pointers, and required = = using an atomic compare-and-swap primitive that works on double the = machine word size (so that you can use another machine word for ABA = resolution), which is non existent for 64 bit systems (there's no = cmpxchg16b AFAIK), hence my question. I admit that I didn't even think about having only one producer and one = = consumer thread and a fixed maximum queue length can simplify things thi= s = much! Turns out that this is all I need. Thanks again, Andras On Wed, 09 Aug 2006 14:10:50 -0600, Jon Watte <hp...@mi...> = wrote: > > And, to confuse things even more, if you have strict aliasing options > turned on, the compiler may even decide to re-order the stores. Thus, > the Totally Safe lock-free FIFO for arbitrary-sized items looks like = > this: > > /* Lock-free FIFO by Jon Watte. > * Stored can be a type of any size. > * Size must be power of 2. > * This FIFO is correct on systems with strongly consistent > * caches (such as Intel). It may require write barriers on > * systems with weakly consistent caches. Insert such a > * barrier in the inline function barrier() if that's the case. > */ > template<typename Stored, size_t Size> > class LockFreeFifo { > public: > LockFreeFifo() { head =3D 0; tail =3D 0; } > > /* Get an item from the FIFO. > * Return true if an item was there and was copied, > * false if the FIFO is empty. > */ > bool get(Stored & out) { > if (head - tail > 0) { > out =3D fifo_[tail & (Size-1)]; > ++tail; > barrier(); /* make sure writer knows FIFO isn't full */ > return true; > } > return false; > } > > /* Put an item into the FIFO. > * Return true if it fit and was copied, > * false if the FIFO is full. > */ > bool put(Stored & in) { > if (head - tail < Size) { > fifo_[head & (Size-1)] =3D in; > barrier(); /* make sure FIFO is updated before head */ > ++head; > barrier(); /* make sure reader can find the new item */ > return true; > } > return false; > } > > private: > > inline void barrier() { > /* If your platform has a weakly consistent cache (i e, > * not Intel) then you need to insert a barrier instruction > * (such as EIEIO on PPC) here. > */ > #warning "Use the intrinsic specific to your platform, if needed." > } > > /* Make these volatile, to avoid strict type aliasing analysis to = = > allow > * the compiler to re-order stores. > */ > volatile unsigned int head; > volatile unsigned int tail; > volatile Stored fifo_[Size]; > }; > > > > Jon Watte wrote: >> Note that the problem is with weakly _consistent_ cahces, not just >> weakly ordered -- i e, if cache line A can flush before cache line B,= it >> doesn't matter, as long as the mutliple CPUs implement cache snooping= to >> stay consistent (which is the case on Intel). On PPC, you may end up >> wanting to use the cache line reservations with a spin loop. |