diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 5dfbaab..8c354f1 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -23,26 +23,42 @@ jobs: # # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] build_type: [Release] c_compiler: [gcc, clang, cl] + include: + # Windows - os: windows-latest c_compiler: cl cpp_compiler: cl + - os: windows-latest + c_compiler: gcc + cpp_compiler: g++ + - os: windows-latest + c_compiler: clang + cpp_compiler: clang++ + + # Linux - os: ubuntu-latest c_compiler: gcc cpp_compiler: g++ - os: ubuntu-latest c_compiler: clang cpp_compiler: clang++ - - os: windows-latest - c_compiler: gcc - - os: windows-latest + + # macOS + - os: macos-latest c_compiler: clang + cpp_compiler: clang++ + exclude: - os: ubuntu-latest c_compiler: cl + - os: macos-latest + c_compiler: cl + - os: macos-latest + c_compiler: gcc steps: - uses: actions/checkout@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c51a70..93c2cef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15) project( ring_buffer - VERSION 1.0.3 + VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) diff --git a/README.md b/README.md index 3c26a69..48b7ee7 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ else() FetchContent_Declare( ring_buffer GIT_REPOSITORY https://github.com/HuRuilizhen/ring_buffer.git - GIT_TAG v1.0.3) # latest stable version + GIT_TAG v0.1.0) # latest stable version FetchContent_MakeAvailable(ring_buffer) endif() diff --git a/tests/mpsc_ring_buffer_test.cc b/tests/mpsc_ring_buffer_test.cc index 9d1d41c..a667024 100644 --- a/tests/mpsc_ring_buffer_test.cc +++ b/tests/mpsc_ring_buffer_test.cc @@ -2,6 +2,10 @@ #include +#include +#include +#include + namespace { struct Counter { @@ -78,6 +82,57 @@ TEST(MPSCRingBufferTest, WrapAround) { EXPECT_FALSE(buffer.tryPop(value)); } +TEST(MPSCRingBufferTest, MPSC) { + constexpr int PRODUCERS = 4; + constexpr int ITEMS_PER_PRODUCER = 500; + constexpr int TOTAL_ITEMS = PRODUCERS * ITEMS_PER_PRODUCER; + constexpr int CAPACITY = 128; + + RingBuffer::MPSCRingBuffer buffer(CAPACITY); + std::atomic produced{0}; + std::atomic consumed{0}; + + std::vector producer_threads; + for (int p = 0; p < PRODUCERS; ++p) { + producer_threads.emplace_back([p, &buffer, &produced]() { + for (int i = 0; i < ITEMS_PER_PRODUCER; ++i) { + int value = p * ITEMS_PER_PRODUCER + i; + while (true) { + if (buffer.tryPush(value)) { + produced.fetch_add(1, std::memory_order_relaxed); + break; + } else { + std::this_thread::yield(); + } + } + } + }); + } + + std::vector results; + results.reserve(TOTAL_ITEMS); + std::thread consumer_thread([&]() { + while (consumed.load(std::memory_order_relaxed) < TOTAL_ITEMS) { + int value; + if (buffer.tryPop(value)) { + results.push_back(value); + consumed.fetch_add(1, std::memory_order_relaxed); + } else { + std::this_thread::yield(); + } + } + }); + + for (auto& t : producer_threads) t.join(); + consumer_thread.join(); + + EXPECT_EQ(results.size(), static_cast(TOTAL_ITEMS)); + std::sort(results.begin(), results.end()); + for (int i = 0; i < TOTAL_ITEMS; ++i) { + EXPECT_EQ(results[i], i); + } +} + TEST(MPSCRingBufferTest, EmplaceBasicType) { int value; RingBuffer::MPSCRingBuffer buffer(2);