1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //
5 //  lock_free_buffer.h
6 //  (C) Copyright 1999-2002 Werner Schweer (ws@seh.de)
7 //  (C) Copyright 2012, 2017 Tim E. Real (terminator356 on users dot sourceforge dot net)
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  as published by the Free Software Foundation; version 2 of
12 //  the License, or (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU General Public License for more details.
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 //=========================================================
24 
25 #ifndef __LOCK_FREE_BUFFER_H__
26 #define __LOCK_FREE_BUFFER_H__
27 
28 //#include <map>
29 #include <atomic>
30 
31 namespace MusECore {
32 
33 
34 //---------------------------------------------------------
35 //   LockFreeBuffer
36 //---------------------------------------------------------
37 
38 template <class T>
39 
40 class LockFreeBuffer
41 {
42       int _capacity;
43       int _id; // Optional ID value.
44       T *_fifo;
45       volatile int _size;
46       int _wIndex;
47       int _rIndex;
48       int _sizeSnapshot;
49       T _dummyRetValue;
50 
51    public:
52       // Start simple with just 2, like a flipping buffer for example.
53       LockFreeBuffer(int capacity = 2, int id = 0)
_capacity(capacity)54       : _capacity(capacity), _id(id)
55       {
56         _dummyRetValue = T();
57         _fifo = new T[_capacity];
58         clear();
59       }
60 
~LockFreeBuffer()61       ~LockFreeBuffer()
62       {
63         if(_fifo)
64           delete[] _fifo;
65       }
66 
id()67       int id() const { return _id; }
68 
69       void setCapacity(int capacity = 2)
70       {
71         if(_fifo)
72           delete _fifo;
73         _fifo = 0;
74         _capacity = capacity;
75         _fifo = new T[_capacity];
76       }
77 
78       // This is only for the writer.
79       // Returns true on fifo overflow
put(const T & item)80       bool put(const T& item)
81       {
82         if (_size < _capacity)
83         {
84           _fifo[_wIndex] = item;
85           _wIndex = (_wIndex + 1) % _capacity;
86           // q_atomic_increment(&_size);
87           ++_size;
88           return false;
89         }
90         return true;
91       }
92 
93       // This is only for the reader.
get()94       T get()
95       {
96         if(_size <= 0)
97           return _dummyRetValue;
98         T item(_fifo[_rIndex]);
99         _rIndex = (_rIndex + 1) % _capacity;
100         --_size;
101         return item;
102       }
103 
104       // This is only for the reader.
105       const T& peek(int n = 0)
106       {
107         const int idx = (_rIndex + n) % _capacity;
108         return _fifo[idx];
109       }
110 
111 //       // This is only for the reader.
112 //       // A non-constant version of peek so that we can modify the items in-place.
113 //       T& peekNonConst(int n = 0)
114 //       {
115 //         const int idx = (_rIndex + n) % _capacity;
116 //         return _fifo[idx];
117 //       }
118 
119       // This is only for the reader.
120       // Returns true if error (nothing to remove).
remove()121       bool remove()
122       {
123         if(_size <= 0)
124           return true;
125         _rIndex = (_rIndex + 1) % _capacity;
126         --_size;
127         return false;
128       }
129 
130       // This is only for the reader.
131       // Returns the number of items in the buffer.
132       // If NOT requesting the size snapshot, this conveniently stores a snapshot (cached) version
133       //  of the size for consistent behaviour later. If requesting the size snapshot, it does not
134       //  update the snapshot itself.
getSize(bool useSizeSnapshot)135       int getSize(bool useSizeSnapshot/* = false*/)
136       {
137         const int sz = useSizeSnapshot ? _sizeSnapshot : _size;
138         if(!useSizeSnapshot)
139           _sizeSnapshot = sz;
140         return sz;
141       }
142       // This is only for the reader.
isEmpty(bool useSizeSnapshot)143       bool isEmpty(bool useSizeSnapshot/* = false*/) const { return useSizeSnapshot ? _sizeSnapshot == 0 : _size == 0; }
144       // This is not thread safe, call it only when it is safe to do so.
clear()145       void clear()         { _size = 0; _sizeSnapshot = 0; _wIndex = 0; _rIndex = 0; }
146       // Clear the 'read' side of the ring buffer, which also clears the size.
147       // NOTE: A corresponding clearWrite() is not provided because
148       //  it is dangerous to reset the size from the sender side -
149       //  the receiver might cache the size, briefly. The sender should
150       //  only grow the size while the receiver should only shrink it.
clearRead()151       void clearRead()     { _size = 0; _sizeSnapshot = 0; _rIndex = _wIndex; }
152 };
153 
154 // // template <class T>
155 // // class LockFreeMultiBuffer
156 // // {
157 // //       int _listCapacity;
158 // //       LockFreeBuffer<T> *_list;
159 // //       //volatile int _size;
160 // //       //int _wIndex;
161 // //       //int _rIndex;
162 // //
163 // //    public:
164 // //       // Start simple with just 2, like a flipping buffer for example.
165 // //       LockFreeMultiBuffer(int listCapacity = 1)
166 // //       {
167 // //         _listCapacity = listCapacity;
168 // //         _list = new LockFreeBuffer<T>[_listCapacity];
169 // //         //clear();
170 // //       }
171 // //       ~LockFreeMultiBuffer()
172 // //       {
173 // //         if(_list)
174 // //           delete[] _list;
175 // //       }
176 // //
177 // //       void setListCapacity(int listCapacity = 1)
178 // //       {
179 // //         if(_list)
180 // //           delete _list;
181 // //         _list = 0;
182 // //         _listCapacity = listCapacity;
183 // //         _list = new LockFreeBuffer<T>[_listCapacity];
184 // //       }
185 // //
186 // // };
187 
188 // template <class T>
189 // class LockFreeMultiBuffer : public std::map<int, LockFreeBuffer<T>*, std::less<int> >
190 // {
191 //   public:
192 //     typedef typename std::map<int, LockFreeBuffer<T>*, std::less<int> > vlist;
193 //     typedef typename vlist::iterator iLockFreeMultiBuffer;
194 //     typedef typename vlist::const_iterator ciLockFreeMultiBuffer;
195 //
196 //   private:
197 // //     int _curId;
198 //     T _dummyRetValue;
199 //
200 //   public:
201 //     //LockFreeMultiBuffer() : _curId(0) { }
202 //     LockFreeMultiBuffer() { _dummyRetValue = T(); }
203 //     ~LockFreeMultiBuffer()
204 //     {
205 //       for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
206 //       {
207 //         if(i->second)
208 //           delete i->second;
209 //       }
210 //     }
211 //
212 //     // Returns new buffer or zero if duplicate id or other error.
213 //     // Start simple with just 2, like a flipping buffer for example.
214 //     LockFreeBuffer<T>* createBuffer(int id, int capacity = 2)
215 //     {
216 //       LockFreeBuffer<T>* buf = new LockFreeBuffer<T>(capacity, id);
217 //       std::pair < iLockFreeMultiBuffer, bool > res =
218 //         vlist::insert(std::pair < const int, LockFreeBuffer<T>* >(buf->id(), buf));
219 // //       if(res.second)
220 // //       {
221 // //         const int c_id = _curId;
222 // //         ++_curId;
223 // //         return c_id;
224 // //       }
225 // //       return -1;
226 //
227 //       if(res.second)
228 //         return buf;
229 //
230 //       delete buf;
231 //       return 0;
232 //     }
233 //
234 //     // Returns true on error.
235 //     bool deleteBuffer(int id)
236 //     {
237 //       //if(id < 0)
238 //       //  return true;
239 //       iLockFreeMultiBuffer i = vlist::find(id);
240 //       if(i == vlist::end())
241 //         return true;
242 //       if(i->second)
243 //         delete i->second;
244 //       vlist::erase(i);
245 //       return false;
246 //     }
247 //
248 //     LockFreeBuffer<T>* findBuffer(int id)
249 //     {
250 //       //if(id < 0)
251 //       //  return 0;
252 //       iLockFreeMultiBuffer i = vlist::find(id);
253 //       if(i == vlist::end())
254 //         return 0;
255 //       return i->second;
256 //     }
257 //
258 //     // Returns true on invalid id.
259 //     bool setCapacity(int id, int capacity = 2)
260 //     {
261 //       //if(id < 0)
262 //       //  return true;
263 //       iLockFreeMultiBuffer i = vlist::find(id);
264 //       if(i == vlist::end())
265 //         return true;
266 //       i->second->setCapacity(capacity);
267 //       return false;
268 //     }
269 //
270 //     // This is only for the writer.
271 //     // Returns true on invalid id, or on fifo overflow of that id's buffer.
272 //     bool put(int id, const T& item)
273 //     {
274 //       //if(id < 0)
275 //       //  return true;
276 //       iLockFreeMultiBuffer i = vlist::find(id);
277 //       if(i == vlist::end())
278 //         return true;
279 //       return i->second->put(item);
280 //     }
281 //
282 //     // This is only for the reader.
283 //     T get(bool useSizeSnapshot/* = false*/)
284 //     {
285 //       iLockFreeMultiBuffer least_i = vlist::end();
286 //       bool is_first = true;
287 //       for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
288 //       {
289 //         LockFreeBuffer<T>* buf = i->second;
290 //         if(!buf || buf->isEmpty(useSizeSnapshot))
291 //           continue;
292 //         const T& temp_val = buf->peek();
293 //         if(is_first)
294 //         {
295 //           is_first = false;
296 //           least_i = i;
297 //           //least_t = temp_val;
298 //           continue;
299 //         }
300 //         else if(temp_val < least_i->second->peek())
301 //           least_i = i;
302 //       }
303 //
304 //       if(least_i != vlist::end())
305 //         return least_i->second->get();
306 //
307 //       return _dummyRetValue;
308 //     }
309 //
310 //     // This is only for the reader.
311 //     const T& peek(bool useSizeSnapshot/* = false*/, int n = 0) // const
312 //     {
313 //       iLockFreeMultiBuffer least_i = vlist::end();
314 //       bool is_first = true;
315 //       int buf_sz;
316 //       for(int idx = 0; idx <= n; ++idx)  // Yes, that's <=
317 //       {
318 //         for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
319 //         {
320 //           LockFreeBuffer<T>* buf = i->second;
321 //           if(!buf)
322 //             continue;
323 //           buf_sz = buf->getSize(useSizeSnapshot);
324 //           if(buf_sz == 0 || n >= buf_sz)
325 //             continue;
326 //           const T& temp_val = buf->peek();
327 //           if(is_first)
328 //           {
329 //             is_first = false;
330 //             least_i = i;
331 //
332 //             //if(idx == n)
333 //             //  break;
334 //             //++idx;
335 //             continue;
336 //           }
337 //           else if(temp_val < least_i->second->peek())
338 //           {
339 //             least_i = i;
340 //
341 //             //if(idx == n)
342 //             //  break;
343 //             //++idx;
344 //           }
345 //         }
346 //         if(idx == n)
347 //           break;
348 //         ++idx;
349 //       }
350 //
351 //       if(least_i != vlist::end())
352 //         return least_i->second->peek();
353 //
354 //       return _dummyRetValue;
355 //     }
356 //
357 // //     // This is only for the reader.
358 // //     // A non-constant version of peek so that we can modify the items in-place.
359 // //     T& peekNonConst(bool useSizeSnapshot/* = false*/, int n = 0) // const
360 // //     {
361 // //       iLockFreeMultiBuffer least_i = vlist::end();
362 // //       bool is_first = true;
363 // //       int buf_sz;
364 // //       for(int idx = 0; idx <= n; ++idx)  // Yes, that's <=
365 // //       {
366 // //         for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
367 // //         {
368 // //           LockFreeBuffer<T>* buf = i->second;
369 // //           if(!buf)
370 // //             continue;
371 // //           buf_sz = buf->getSize(useSizeSnapshot);
372 // //           if(buf_sz == 0 || n >= buf_sz)
373 // //             continue;
374 // //           T& temp_val = buf->peekNonConst();
375 // //           if(is_first)
376 // //           {
377 // //             is_first = false;
378 // //             least_i = i;
379 // //
380 // //             //if(idx == n)
381 // //             //  break;
382 // //             //++idx;
383 // //             continue;
384 // //           }
385 // //           else if(temp_val < least_i->second->peekNonConst())
386 // //           {
387 // //             least_i = i;
388 // //
389 // //             //if(idx == n)
390 // //             //  break;
391 // //             //++idx;
392 // //           }
393 // //         }
394 // //         if(idx == n)
395 // //           break;
396 // //         ++idx;
397 // //       }
398 // //
399 // //       if(least_i != vlist::end())
400 // //         return least_i->second->peekNonConst();
401 // //
402 // //       return _dummyRetValue;
403 // //     }
404 //
405 //     // This is only for the reader.
406 //     // Returns true if error (nothing to remove).
407 //     bool remove(bool useSizeSnapshot/* = false*/)
408 //     {
409 //       iLockFreeMultiBuffer least_i = vlist::end();
410 //       bool is_first = true;
411 //       for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
412 //       {
413 //         LockFreeBuffer<T>* buf = i->second;
414 //         if(!buf || buf->isEmpty(useSizeSnapshot))
415 //           continue;
416 //         const T& temp_val = buf->peek();
417 //         if(is_first)
418 //         {
419 //           is_first = false;
420 //           least_i = i;
421 //           continue;
422 //         }
423 //         else if(temp_val < least_i->second->peek())
424 //           least_i = i;
425 //       }
426 //
427 //       if(least_i != vlist::end())
428 //         return least_i->second->remove();
429 //
430 //       return true;
431 //     }
432 //
433 //     // This is only for the reader.
434 //     // Returns the total number of items in the buffers.
435 //     // Also conveniently stores a cached version of the size for consistent behaviour later.
436 //     int getSize(bool useSizeSnapshot/* = false*/) const
437 //     {
438 //       int sz = 0;
439 //       // Hm, maybe not so accurate, sizes may be susceptable to
440 //       //  asynchronous change as we iterate here...
441 //       for(ciLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
442 //       {
443 //         if(LockFreeBuffer<T>* buf = i->second)
444 //           sz += buf->getSize(useSizeSnapshot);
445 //       }
446 //       return sz;
447 //     }
448 //
449 //     // This is only for the reader.
450 //     bool isEmpty(bool useSizeSnapshot/* = false*/) const
451 //     {
452 //       // Hm, maybe not so accurate, sizes may be susceptable to
453 //       //  asynchronous change as we iterate here...
454 //       for(ciLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
455 //       {
456 //         if(const LockFreeBuffer<T>* buf = i->second)
457 //         {
458 //           if(!buf->isEmpty(useSizeSnapshot))
459 //             return false;
460 //         }
461 //       }
462 //       return true;
463 //     }
464 //
465 //     // This is not thread safe, call it only when it is safe to do so.
466 //     void clear()
467 //     {
468 //       for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
469 //       {
470 //         if(LockFreeBuffer<T>* buf = i->second)
471 //           buf->clear();
472 //       }
473 //     }
474 //
475 //     // Clear the 'read' side of the ring buffer, which also clears the size.
476 //     // NOTE: A corresponding clearWrite() is not provided because
477 //     //  it is dangerous to reset the size from the sender side -
478 //     //  the receiver might cache the size, briefly. The sender should
479 //     //  only grow the size while the receiver should only shrink it.
480 //     void clearRead()
481 //     {
482 //       for(iLockFreeMultiBuffer i = vlist::begin(); i != vlist::end(); ++i)
483 //       {
484 //         if(LockFreeBuffer<T>* buf = i->second)
485 //           buf->clearRead();
486 //       }
487 //     }
488 // };
489 
490 //---------------------------------------------------------
491 //   LockFreeMPSCBuffer
492 //   A lock-free Multi-Producer Single-Consumer buffer.
493 //   Similar to a FIFO or Ring Buffer, but uses a fixed number of 'bins'.
494 //   There are no position counters or modulo operations.
495 //   There is no size or peek method.
496 //   It is intended to be fully consumed at reading time.
497 //---------------------------------------------------------
498 
499 template <class T, unsigned int capacity>
500 class LockFreeMPSCBuffer
501 {
502       T _array[capacity];
503       std::atomic<bool> _inUse[capacity];
504       std::atomic<bool> _hasData[capacity];
505 
506    public:
LockFreeMPSCBuffer()507       LockFreeMPSCBuffer() { clear(); }
508 
509       // Returns the buffer capacity.
bufferCapacity()510       unsigned int bufferCapacity() const { return capacity; }
511 
512       // This is only for the writer.
513       // Returns true on success, false if buffer overflow.
put(const T & item)514       bool put(const T& item)
515       {
516         bool expected;
517         for(unsigned int i = 0; i < capacity; ++i)
518         {
519           // Expecting a not-in-use bin. Must reset expected each time.
520           expected = false;
521           // Safely check and set the bin's inUse flag.
522           if(_inUse[i].compare_exchange_strong(expected, true))
523           {
524             // Bin was not in use, now safely marked as in use. Now set the item.
525             _array[i] = item;
526             // Safely set the hasData flag for the reader to examine.
527             _hasData[i].store(true);
528             // Success.
529             return true;
530           }
531         }
532         // Sorry, all bins were full. A buffer overflow condition.
533         return false;
534       }
535 
536       // This is only for the reader.
537       // Returns true on success, false if there was no data
538       //  available at the bin index or other error.
get(T & dst,unsigned int index)539       bool get(T& dst, unsigned int index)
540       {
541         if(index >= capacity)
542           return false;
543 
544         // Expecting hasData true.
545         bool expected = true;
546         // Safely check if there is data in the bin, and reset the
547         //  bin's hasData and inUse flags. Clear the hasData flag first !!!
548         if(_hasData[index].compare_exchange_strong(expected, false))
549         {
550           // It is safe to store the value in the destination.
551           dst = _array[index];
552           // Now clear the inUse flag !!!
553           _inUse[index].store(false);
554           // Success.
555           return true;
556         }
557         // Sorry, there was no data available in that bin.
558         return false;
559       }
560 
561       // This is only for the reader.
562       // Returns true on success.
remove(unsigned int index)563       bool remove(unsigned int index)
564       {
565         if(index >= capacity)
566           return false;
567 
568         // Expecting hasData true.
569         bool expected = true;
570         // Safely check and reset the bin's hasData and inUse flags.
571         if(_hasData[index].compare_exchange_strong(expected, false))
572         {
573           _inUse[index].store(false);
574           // Success.
575           return true;
576         }
577         // Sorry, there was no data available in that bin.
578         return false;
579       }
580 
581       // Not thread safe. Only call when safe to do so,
582       //  like constructor etc.
clear()583       void clear()
584       {
585         for(unsigned int i = 0; i < capacity; ++i)
586         {
587           // Clear the hasData flag first !!!
588           _hasData[i].store(false);
589           // Now clear the inUse flag !!!
590           _inUse[i].store(false);
591         }
592       }
593 
594       // This is only for the reader.
clearRead()595       void clearRead()
596       {
597         bool expected;
598         for(unsigned int i = 0; i < capacity; ++i)
599         {
600           // Expecting hasData true. Must reset expected each time.
601           expected = true;
602           // Safely check and reset the bin's hasData and inUse flags.
603           if(_hasData[i].compare_exchange_strong(expected, false))
604             _inUse[i].store(false);
605         }
606       }
607 };
608 
609 //---------------------------------------------------------
610 //   LockFreeMPSCRingBuffer
611 //---------------------------------------------------------
612 
613 template <class T>
614 
615 class LockFreeMPSCRingBuffer
616 {
617       unsigned int _capacity;
618       T *_fifo;
619       std::atomic<unsigned int> _size;
620       std::atomic<unsigned int> _wIndex;
621       std::atomic<unsigned int> _rIndex;
622       unsigned int _capacityMask;
623       unsigned int _sizeSnapshot;
624 
625       // Rounds to the nearest or equal power of 2.
626       // For 0, 1, and 2, always returns 2.
roundCapacity(unsigned int reqCap)627       unsigned int roundCapacity(unsigned int reqCap) const
628       {
629         unsigned int i;
630         for(i = 1; (1U << i) < reqCap; i++);
631         return 1U << i;
632       }
633 
634    public:
635       // Start simple with just 2, like a flipping buffer for example.
636       LockFreeMPSCRingBuffer(unsigned int capacity = 2)
637       {
638         _capacity = roundCapacity(capacity);
639         _capacityMask = _capacity - 1;
640         _fifo = new T[_capacity];
641         clear();
642       }
643 
~LockFreeMPSCRingBuffer()644       ~LockFreeMPSCRingBuffer()
645       {
646         if(_fifo)
647           delete[] _fifo;
648       }
649 
650       void setCapacity(unsigned int capacity = 2)
651       {
652         if(_fifo)
653           delete[] _fifo;
654         _fifo = 0;
655         _capacity = roundCapacity(capacity);
656         _capacityMask = _capacity - 1;
657         _fifo = new T[_capacity];
658       }
659 
660       // This is only for the writer.
661       // Returns true on success, false on fifo overflow or other error.
put(const T & item)662       bool put(const T& item)
663       {
664         // Buffer full? Overflow condition.
665         if(_size.load() >= _capacity)
666           return false;
667 
668         // Safely read, then increment, the current write position.
669         //std::atomic<unsigned int> pos = _wIndex++;
670         unsigned int pos = _wIndex++;
671         // Mask the position for a circular effect.
672         pos &= _capacityMask;
673         // Store the item in that position.
674         _fifo[pos] = item;
675         // Now safely increment the size.
676         _size++;
677         // Success.
678         return true;
679       }
680 
681       // This is only for the reader.
682       // Returns true on success, false if nothing to read or other error.
683       // NOTE: This is not multi-reader safe. Yet.
get(T & dst)684       bool get(T& dst)
685       {
686         // Nothing to read?
687         if(_size.load() == 0)
688           return false;
689 
690         // Safely read, then increment, the current read position.
691         //std::atomic<unsigned int> pos = _rIndex++;
692         unsigned int pos = _rIndex++;
693         // Mask the position for a circular effect.
694         pos &= _capacityMask;
695         // Store the item in that position into the destination.
696         dst = _fifo[pos];
697         // Now safely decrement the size.
698         _size--;
699         // Success.
700         return true;
701       }
702 
703       // This is only for the reader.
704       // NOTE: This is not multi-reader safe. Yet.
705       const T& peek(unsigned int n = 0)
706       {
707         // Safely read the current read position.
708         //std::atomic<unsigned int> pos = _rIndex.load();
709         unsigned int pos = _rIndex.load();
710         // Add the desired position.
711         pos += n;
712         // Mask the position for a circular effect.
713         pos &= _capacityMask;
714         return _fifo[pos];
715       }
716 
717 //       // This is only for the reader.
718 //       // A non-constant version of peek so that we can modify the items in-place.
719 //       T& peekNonConst(int n = 0)
720 //       {
721 //         const int idx = (_rIndex + n) % _capacity;
722 //         return _fifo[idx];
723 //       }
724 
725       // This is only for the reader.
726       // Returns true on success or false if nothing to remove or other error.
remove()727       bool remove()
728       {
729         // Nothing to read?
730         if(_size.load() == 0)
731           return false;
732 
733         // Safely increment the current read position.
734         _rIndex++;
735         // Now safely decrement the size.
736         _size--;
737         // Success.
738         return true;
739       }
740 
741       // This is only for the reader.
742       // Returns the number of items in the buffer.
743       // If NOT requesting the size snapshot, this conveniently stores a snapshot (cached) version
744       //  of the size for consistent behaviour later. If requesting the size snapshot, it does not
745       //  update the snapshot itself.
getSize(bool useSizeSnapshot)746       unsigned int getSize(bool useSizeSnapshot/* = false*/)
747       {
748         const unsigned int sz = useSizeSnapshot ? _sizeSnapshot : _size.load();
749         if(!useSizeSnapshot)
750           _sizeSnapshot = sz;
751         return sz;
752       }
753       // This is only for the reader.
isEmpty(bool useSizeSnapshot)754       bool isEmpty(bool useSizeSnapshot/* = false*/) const { return useSizeSnapshot ? _sizeSnapshot == 0 : _size.load() == 0; }
755       // This is not thread safe, call it only when it is safe to do so.
clear()756       void clear() { _size.store(0); _sizeSnapshot = 0; _wIndex.store(0); _rIndex.store(0); }
757       // This is only for the reader.
758       // Clear the 'read' side of the ring buffer, which also clears the size.
759       // NOTE: A corresponding clearWrite() is not provided because it is dangerous to reset
760       //  the size from the sender side - the receiver might cache the size, briefly.
761       // The sender should only grow the size while the receiver should only shrink it.
762       //void clearRead() { _size = 0; _sizeSnapshot = 0; _rIndex = _wIndex; }
clearRead()763       void clearRead() { _size.store(0); _sizeSnapshot = 0; _rIndex.store(_wIndex); }
764 };
765 
766 } // namespace MusECore
767 
768 #endif
769 
770