Home > Enterprise >  Why doesn't this C barrier implementation work?
Why doesn't this C barrier implementation work?

Time:11-12

Why doesn't the following barrier implementation work:

void JoinQuery::barrier() {
    std::unique_lock<std::mutex> lk(barrier_mutex);
    barrier_count  ;
    if (barrier_count == NUM_THREADS) {
        barrier_count = 0;
        lk.unlock();
        barrier_cv.notify_all();
    } else {
        barrier_cv.wait(lk, [this] { return barrier_count == 0; });
    }
}

However it works if I use a second variable to track the condition of all threads arriving.

But I don't know why this is necessary. It should be impossible for a thread to see barrier_count == 0 before all threads have arrived.

CodePudding user response:

Is this supposed to be a one-time barrier? Where once N threads have hit the barrier, all further calls are non blocking? In that case, you would want a bool flag indicating that has tripped, and check that as well.

The problem is that if barrier() is called more than NUM_THREAD times, it will increase barrier_count again, resulting in any waiting threads going back to sleep.

CodePudding user response:

It works well with 1000 threads

#include <vector>
#include <thread>
#include <condition_variable>
using namespace std;

int NUM_THREADS = 1000;

class JoinQuery {
    mutex               barrier_mutex;
    condition_variable  barrier_cv;
    int barrier_count = 0;
public:
    void barrier(int num) {
        std::unique_lock<std::mutex> lk(barrier_mutex);
        barrier_count  ;
        if (barrier_count == NUM_THREADS) {
            barrier_count = 0;
            barrier_cv.notify_all();
        } else {
            barrier_cv.wait(lk, [this] { return barrier_count == 0; });
            printf("wake num=%d\n", num);
        }
    }
};

int main(){
    JoinQuery       jq;
    vector<thread>  ts;
    for (int i = 0; i < NUM_THREADS; i  ) {
        ts.push_back(thread(&JoinQuery::barrier, ref(jq), i));
    }
    for (auto& t : ts) {
        t.join();
    }
}
  • Related