cameron314 / concurrentqueue

A fast multi-producer, multi-consumer lock-free concurrent queue for C++11
Other
9.86k stars 1.69k forks source link

try_enqueue takes up to 1024 elements, regardless of initial capacity #379

Closed devingryu closed 5 months ago

devingryu commented 5 months ago
#include "concurrentqueue.h"
#include <cstdint>
#include <cstdio>

int main() {
    moodycamel::ConcurrentQueue<int32_t> rb(2048);
    int count = 0;
    for (int i=0;i<2000;i++) {
        while(!rb.try_enqueue(0)) {}
        count++;
        printf("count: %d\n", count);
    }
}

I've run this block of code, and this never ends after printing count:1024. Changing capacity to larger value(4096, 8192...) doesn't make any changes to output.

What am I missing? Thanks in advance.

Edit: I found that increasing IMPLICIT_INITIAL_INDEX_SIZE in Trait solves the issue by investigating code. Specifically, min(BLOCK_SIZE * IMPLICIT_INITIAL_INDEX_SIZE, capacity) elements are accepted by try_enqueue().

Is this the correct way to contain over 1024 elements with implicit producer?

struct MyTrait : moodycamel::ConcurrentQueueDefaultTraits {
    static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 64;
};

int main() {
    moodycamel::ConcurrentQueue<int32_t, MyTrait> rb(2048);
    int count = 0;

    for (int i=0;i<2048;i++) {
        while(!rb.try_enqueue(0)) {}
        count++;
        printf("count: %d\n", count);
    }
}
cameron314 commented 5 months ago

Yes, try_enqueue cannot allocate any memory, and there needs to be space in the producer's block index as well as a block itself.

Have a look at the three-argument constructor to make sure enough blocks are allocated when producing from multiple threads.

An index size of 64 or greater should be fine here.

devingryu commented 5 months ago

Thanks for your kind answer! The problem is solved, but I have one more question to ask.

Is there a reason for defining the Initial Block Index Size separately in struct Trait? If we just define the Initial Capacity and Block Size, can't we also determine the required Initial Block Index Size?

cameron314 commented 5 months ago

The index is per producer. We could in theory deduce the largest index possibly required in the worst case that all blocks are in one producer, and use that for all producers, but that's just not how I had designed it originally.

devingryu commented 5 months ago

I wasn't aware that index is per producer. Now I understand why you designed in that way.

Thanks!