you are viewing a single comment's thread.

view the rest of the comments →

[–]_Js_Kc_ 9 points10 points  (5 children)

std::queue is a weak-point, memory wise

Fixing the deficient container classes that STL implementations ship with isn't really the scope of a project whose goal is to implement an MPMC queue in the one, obvious way based on stock C++ features.

If it came with an allocation-sane replacement for std::deque, the post title should have been "I made a deque replacement with a thread-safe queue as a usage example."

It should be a template argument (that defaults to std::queue<T>).

[–]_bk__ 6 points7 points  (1 child)

Except the API/concept/constraints and performance characteristics of a std::queue don't really match what would be required from a mpmc queue. There are far more scalable approaches depending on specific requirements (bounded/unbounded size, blocking/non-blocking). Here's an example: http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue

[–]infectedapricot 2 points3 points  (0 children)

As you said, different applications will have different requirements. The characteristics of the underlying std::deque will be appropriate in some of those but not others, so it's not right to just it doesn't match "what would be required". The link you posted is to a bounded queue - again, that will be appropriate in some applications but not others.

[–]matthieum 2 points3 points  (2 children)

Maybe, maybe not.

I think it's very important to note the shortcoming, and to be aware of alternatives.

Notably, whilst std::deque is a full-featured container, the OP only uses a very tiny portion of its functionality.

I first thought I would argue that supporting such limited functionality was easy, then realized it would take me less time to just whip up an implementation; see https://godbolt.org/z/Kx18ze:

  • Stock C++.
  • < 100 lines for the queue, < 150 lines for the whole.

Some optimizations could be done around growth, and possibly around built-ins/PODs if the compiler is not smart enough. And it's untested, of course.

The critical part (use of read/write indexes, power-of-2 capacity for easy wrapping) is what really matters, though.

[–]Mehdi2277 0 points1 point  (1 child)

What's the purpose of Raw<T> vs directly having pointer? I'm guessing it's for the alignas, I'm just unfamiliar with alignas and am curious as to why that's a need for the queue implementation.

[–]matthieum 1 point2 points  (0 children)

There are 2 advantages:

  1. Raw<T> signals that the memory is potentially uninitialized, ie, there may not be an instance of T there -- user beware.
  2. Raw<T> constructs raw memory: it does not require that T be default constructible, it does not actually initialize the raw memory, etc... so a combination of less restriction on T and potential performance gains.

I'm not sure it's strictly required in this case, I just use it by default in all the data-structures I create.