My program is structured like this: there are `M` producer threads, each of which computes a section of an object `O` with index `i` `O[i]`. When a specific `O[i]` is completed by all producers, it is put in a ring buffer, which is consumed by `N` threads. When all consumers are done with a specific `O[i]` can be discarded.

**There must be no inter-group synchronization**, that producers need not to synchronize work on a single `O[i]`, as well as consumers. The objects must appear in order in the ring though. Also, the speed of production and consumption can vary wildly, so a consumer that cannot acquire an element from the ring must block, and if a producer is about to start working on an element but the ring is full, it shall block. In all the other cases, insertion and removal should be lock free.


----------


Here's what I came up with C++11. *I seek for advice especially on the usage of the various relaxed memory models*.

https://raw.githubusercontent.com/pisto/proper/master/multiqueue.hpp

An actual usage with two queues can be found [here][1] (the schema is main thread => `leviqueue` => `N * producer` => `numthreads * consumer`, where `N` is `std::thread::hardware_concurrency()`).

The class doesn't try to manage the actual objects on the behalf of the user, but just handles the indexes `i` of each object.

The queue [constructor][2] is `multiqueue::multiqueue(unsigned int inthread, unsigned int outthread, size_t ringsize, size_t unblockproducer = 0, size_t unblockconsumer = 0)`, where besides the obvious parameters

 - `unblockproducer` indicates when the ring is "almost empty", so if too fast producers were previously blocked they should be awaken, and
 - `unblockconsumer` the opposite situation in case that consumers were blocked for starvation.

Each producer has a thread local index in the ring, and must acquire and release it, with [`acquire_producer()`][3], [`release_producer()`][4], [`acquire_consumer()`][5], [`release_consumer()`][6]. EOF is signaled by the producer with the [`eof()`][7] member function (which is an acquire - release operation), and when a consumer encounters EOF, `acquire_consumer()` returns `-1`.


----------


I have checked the assembly and my code seems not to produce any `mfence` instruction on x86, only some `lock` when incrementing reference counting. Is that correct and expected?

  [1]: https://github.com/pisto/proper/blob/master/coalesce.cpp#L284-L402
  [2]: https://github.com/pisto/proper/blob/master/multiqueue.hpp#L41
  [3]: https://github.com/pisto/proper/blob/master/multiqueue.hpp#L68
  [4]: https://github.com/pisto/proper/blob/master/multiqueue.hpp#L74
  [5]: https://github.com/pisto/proper/blob/master/multiqueue.hpp#L50
  [6]: https://github.com/pisto/proper/blob/master/multiqueue.hpp#L60
  [7]: https://github.com/pisto/proper/blob/master/multiqueue.hpp#L80