rigtorp / MPMCQueue

A bounded multi-producer multi-consumer concurrent queue written in C++11
MIT License
1.15k stars 159 forks source link

`try_pop` returns false when the queue is not empty. #46

Open hazby2002 opened 7 months ago

hazby2002 commented 7 months ago

I use a semaphore (std::counting_semaphore in c++20 for convenience here) to make sure that the queue is not empty. There is a simple example:

#include <thread>
#include <vector>
#include <iostream>
#include "rigtorp/MPMCQueue.h"

int main() {
  rigtorp::MPMCQueue<int> queue(2333);
  std::counting_semaphore<> sem{0};

  std::thread reader([&]{
    int num = 100000;
    while (num--) {
      sem.acquire();
      int x;
      if (!queue.try_pop(x)) {
        std::cout << queue.size() << "\n";
        std::cout << "error\n";
        exit(-1);
      }
    }
  });

  std::vector<std::thread> writers;
  for (int i = 0; i < 10; i++) {
    writers.emplace_back([&] {
      int num = 10000;
      while (num--) {
        queue.push(num);
        sem.release();
      }
    });
  }

  reader.join();
  for (auto& writer : writers) writer.join();

  std::cout << "ok\n";
}

The code can print "error". Such result can be reproduced in godbolt.

I think it caused by release-acquire memory order of atomic operations, but I am not sure how to solve it.