TEST(MpscQueueConcurrentTest, shouldExchangeMessages)
{
    AERON_DECL_ALIGNED(aeron_mpsc_concurrent_array_queue_t q, 16);

    ASSERT_EQ(aeron_mpsc_concurrent_array_queue_init(&q, CAPACITY), 0);

    std::atomic<int> countDown(NUM_PUBLISHERS);
    std::atomic<unsigned int> publisherId(0);

    std::vector<std::thread> threads;
    size_t msgCount = 0;
    uint32_t counts[NUM_PUBLISHERS];

    for (int i = 0; i < NUM_PUBLISHERS; i++)
    {
        counts[i] = 0;
    }

    for (int i = 0; i < NUM_PUBLISHERS; i++)
    {
        threads.push_back(
            std::thread(
                [&]()
                {
                    uint32_t id = publisherId.fetch_add(1);

                    countDown--;
                    while (countDown > 0)
                    {
                        std::this_thread::yield(); // spin until we is ready
                    }

                    for (uint32_t m = 0; m < NUM_MESSAGES_PER_PUBLISHER; m++)
                    {
                        mpsc_concurrent_test_data_t *data = new mpsc_concurrent_test_data_t;

                        data->id = id;
                        data->num = m;

                        while (AERON_OFFER_SUCCESS != aeron_mpsc_concurrent_array_queue_offer(&q, data))
                        {
                            std::this_thread::yield();
                        }
                    }
                }));
    }

    while (msgCount < (NUM_MESSAGES_PER_PUBLISHER * NUM_PUBLISHERS))
    {
        const uint64_t drainCount =
            aeron_mpsc_concurrent_array_queue_drain(&q, mpsc_queue_concurrent_handler, counts, CAPACITY);

        if (0 == drainCount)
        {
            std::this_thread::yield();
        }

        msgCount += drainCount;
    }

    // wait for all threads to finish
    for (std::thread &thr: threads)
    {
        thr.join();
    }

    aeron_mpsc_concurrent_array_queue_close(&q);
}
TEST(MpscRbConcurrentTest, shouldExchangeMessages)
{
    AERON_DECL_ALIGNED(buffer_t mpsc_buffer, 16);
    mpsc_buffer.fill(0);

    aeron_mpsc_rb_t rb;
    ASSERT_EQ(aeron_mpsc_rb_init(&rb, mpsc_buffer.data(), mpsc_buffer.size()), 0);

    std::atomic<int> countDown(NUM_PUBLISHERS);
    std::atomic<unsigned int> publisherId(0);

    std::vector<std::thread> threads;
    size_t msgCount = 0;
    uint32_t counts[NUM_PUBLISHERS];

    for (int i = 0; i < NUM_PUBLISHERS; i++)
    {
        counts[i] = 0;
    }

    for (int i = 0; i < NUM_PUBLISHERS; i++)
    {
        threads.push_back(
            std::thread(
                [&]()
                {
                    AERON_DECL_ALIGNED(buffer_t buffer, 16);
                    buffer.fill(0);
                    uint32_t id = publisherId.fetch_add(1);

                    countDown--;
                    while (countDown > 0)
                    {
                        std::this_thread::yield();
                    }

                    mpsc_concurrent_test_data_t *data = (mpsc_concurrent_test_data_t *)(buffer.data());

                    for (uint32_t m = 0; m < NUM_MESSAGES_PER_PUBLISHER; m++)
                    {
                        data->id = id;
                        data->num = m;

                        while (AERON_RB_SUCCESS != aeron_mpsc_rb_write(
                            &rb, MSG_TYPE_ID, buffer.data(), sizeof(mpsc_concurrent_test_data_t)))
                        {
                            std::this_thread::yield();
                        }
                    }
                }));
    }

    while (msgCount < (NUM_MESSAGES_PER_PUBLISHER * NUM_PUBLISHERS))
    {
        const size_t readCount = aeron_mpsc_rb_read(
            &rb, mpsc_rb_concurrent_handler, counts, std::numeric_limits<size_t>::max());

        if (0 == readCount)
        {
            std::this_thread::yield();
        }

        msgCount += readCount;
    }

    for (std::thread &thr: threads)
    {
        thr.join();
    }
}