Short version:
I am trying to replace std :: atomic from C ++ 11 used in an implementation without blocking, one manufacturer, one user queue from here . How to replace this with boost::atomic ?
Long version:
I am trying to get the best performance from our workflow application. Each thread has its own task queue. We must synchronize the use of locks before we perform the de-tool / enqueue of each task.
Then I found an article by Herb Sutter about free queuing. It seems to be the perfect replacement. But the code uses std::atomic from C ++ 11, which I could not present to the project at this time.
More googling led to some examples, such as this one for Linux (echelon's) and this one for Windows (TINESWARE) . Both use platform-specific designs, such as WinAPI InterlockedExchangePointer and GCC __sync_lock_test_and_set .
I only need to support Windows and Linux, so maybe I can succeed with some #ifdef s. But I thought it would be better to use what boost::atomic offers. Boost Atomic is not yet part of the official Boost library. So I downloaded the source from http://www.chaoticmind.net/~hcb/projects/boost.atomic/ and used the include files with my project.
This is what I get so far:
#pragma once #include <boost/atomic.hpp> template <typename T> class LockFreeQueue { private: struct Node { Node(T val) : value(val), next(NULL) { } T value; Node* next; }; Node* first; // for producer only boost::atomic<Node*> divider; // shared boost::atomic<Node*> last; // shared public: LockFreeQueue() { first = new Node(T()); divider = first; last= first; } ~LockFreeQueue() { while(first != NULL) // release the list { Node* tmp = first; first = tmp->next; delete tmp; } } void Produce(const T& t) { last.load()->next = new Node(t); // add the new item last = last.load()->next; while(first != divider) // trim unused nodes { Node* tmp = first; first = first->next; delete tmp; } } bool Consume(T& result) { if(divider != last) // if queue is nonempty { result = divider.load()->next->value; // C: copy it back divider = divider.load()->next; return true; // and report success } return false; // else report empty } };
Some changes:
boost::atomic<Node*> divider; // shared boost::atomic<Node*> last; // shared
and
last.load()->next = new Node(t);
and
result = divider.load()->next->value;
Am I using load () (and implicit storage ()) from boost :: atomic right here? Can we say that this is equivalent to the original C-11 Sutter open queue?
PS. I studied a lot of threads on SO, but none of them can serve as an example for boost :: atomic and free-queue queue.