diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/yqueue.hpp | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/src/yqueue.hpp b/src/yqueue.hpp index 45b2b18..cb20697 100644 --- a/src/yqueue.hpp +++ b/src/yqueue.hpp @@ -24,6 +24,7 @@ #include <stddef.h> #include "err.hpp" +#include "atomic_ptr.hpp" namespace zmq { @@ -37,9 +38,9 @@ namespace zmq // pop on the empty queue and that both threads don't access the same // element in unsynchronised manner. // - // T is the type of the object in the queue + // T is the type of the object in the queue. // N is granularity of the queue (how many pushes have to be done till - // actual memory allocation is required) + // actual memory allocation is required). template <typename T, int N> class yqueue_t { @@ -69,6 +70,10 @@ namespace zmq begin_chunk = begin_chunk->next; delete o; } + + chunk_t *sc = spare_chunk.xchg (NULL); + if (sc) + delete sc; } // Returns reference to the front element of the queue. @@ -94,8 +99,13 @@ namespace zmq if (++end_pos != N) return; - end_chunk->next = new (std::nothrow) chunk_t; - zmq_assert (end_chunk->next); + chunk_t *sc = spare_chunk.xchg (NULL); + if (sc) { + end_chunk->next = sc; + } else { + end_chunk->next = new (std::nothrow) chunk_t; + zmq_assert (end_chunk->next); + } end_chunk = end_chunk->next; end_pos = 0; } @@ -107,7 +117,13 @@ namespace zmq chunk_t *o = begin_chunk; begin_chunk = begin_chunk->next; begin_pos = 0; - delete o; + + // 'o' has been more recently used than spare_chunk, + // so for cache reasons we'll get rid of the spare and + // use 'o' as the spare. + chunk_t *cs = spare_chunk.xchg (o); + if (cs) + delete cs; } } @@ -131,6 +147,11 @@ namespace zmq chunk_t *end_chunk; int end_pos; + // People are likely to produce and consume at similar rates. In + // this scenario holding onto the most recently freed chunk saves + // us from having to call new/delete. + atomic_ptr_t<chunk_t> spare_chunk; + // Disable copying of yqueue. yqueue_t (const yqueue_t&); void operator = (const yqueue_t&); |