1

I have 4-threads in my program. I want to execute all of them once and once all of them are executed then only I want to enter the next iteration of execution.

I got a code on stack overflow that implements the boost::barrier function in C++. But it does not seem to work for me. For one iteration it works fine. But for the next iteration, the program execution just hangs.

//Here is my top code:

#include <iostream>
#include <stdio.h>
#include <thread>
#include "abc_func.hpp"
#include <vector>
using namespace std;

int main() {
    abc obj1;
        obj1.num_threads(4);
    std::thread t1([&obj1](){
        for (int i=0; i<5; i++) {
        while (!obj1.abc_write(1));
        };
    });
    std::thread t2([&obj1](){
        for (int i=0; i<5; i++) {
        while (!obj1.abc_read(2));
        };
    });
    std::thread t3([&obj1](){
        for (int i=0; i<5; i++) {
        while (!obj1.abc_write(3));
        };
    });
    std::thread t4([&obj1](){
        for (int i=0; i<5; i++) {
        while (!obj1.abc_read(4));
        };
    });
    t1.join();
    t2.join();
    t3.join();
        t4.join();


//  cout << "done: " << obj1.done << endl;

    // cout << "done: " << obj2.done << endl;

    // cout << "wr_count: " << obj1.wr_count << endl;
    return 0;   
}

// Here is the abc_func.hpp

#include <iostream>
#include <stdio.h>
#include <thread>
#include <barrier.hpp>

using namespace std;
class abc {
    size_t n_threads;

    public:
    abc() : n_threads(0) {};

        void num_threads (size_t l) {
          n_threads = l;
        }

    Barrier task_bar{n_threads};

    bool abc_write (auto id) {
          thread_local int wr_count = 0;
          if (wr_count == 1) {
            std::cout << "write thread waiting" << id << endl;
            task_bar.Wait();
            wr_count = 0;
          };
      std::cout << "write thread running " << id << endl;
          ++wr_count;
      return true;
    }

    bool abc_read (auto id) {
          thread_local int rd_count=0;
          if (rd_count == 1) {
            std::cout << "read thread waiting" << id << endl;
            task_bar.Wait();
            rd_count = 0;
          };
      std::cout << "read thread running " << id << endl;
          ++rd_count;
      return true;
    }

};

// and the barrier class code which I got on stack overflow

#include <thread>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <stdio.h>

class Barrier {
public:
    explicit Barrier(std::size_t iCount) : 
      mThreshold(iCount), 
      mCount(iCount), 
      mGeneration(0) {
    }

    void Wait() {
        std::unique_lock<std::mutex> lLock{mMutex};
        auto lGen = mGeneration;
        if (!--mCount) {
            mGeneration++;
            mCount = mThreshold;
            mCond.notify_all();
        } else {
            mCond.wait(lLock, [this, lGen] { return lGen != mGeneration; });
        }
    }

private:
    std::mutex mMutex;
    std::condition_variable mCond;
    std::size_t mThreshold;
    std::size_t mCount;
    std::size_t mGeneration;
};
Tushar
  • 415
  • 2
  • 16
  • Why are you doing "using namespace std;" and "std::" at the same time... – Rafael Feb 09 '18 at 19:36
  • @FredLarson I looked at https://stackoverflow.com/questions/24465533/implementing-boostbarrier-in-c11 – Tushar Feb 09 '18 at 19:38
  • I was also wondering why each file has `#include ` when nothing from stdio.h appears to be used. – Fred Larson Feb 09 '18 at 19:38
  • @FredLarson I just copy paste my headers from previous files. – Tushar Feb 09 '18 at 19:39
  • @Tushar Both of those are bad practices. The [concurrency TS](http://en.cppreference.com/w/cpp/experimental/concurrency) adds latches and barriers to C++. If you have a new enough compiler, you might be able to use that. – Praetorian Feb 09 '18 at 19:58
  • @Praetorian I just learnt about std::experimental::barrier and I tried to use it. But it gives me error in the `#include ` header. Maybe I need to add some other flag with G++. – Tushar Feb 09 '18 at 19:59
  • http://en.cppreference.com/w/cpp/atomic/atomic_thread_fence – Jesper Juhl Feb 09 '18 at 20:06
  • Saying *it gives me error* is not useful, how can anyone help you with no other information? Please update the question with details like g++ version, the command line you're using for compiling and copy-paste the exact error message you see. – Praetorian Feb 09 '18 at 20:17
  • If you just want to set them all in motion and wait for them to finish, what's wrong with [std::thread::join](http://en.cppreference.com/w/cpp/thread/thread/join)? – Jesper Juhl Feb 09 '18 at 20:19
  • @OlafDietsche Sorry about that. Accidentally copied something else. I fixed it. thanks! – Tushar Feb 09 '18 at 20:29
  • @Praetorian concurrency TS isn't really available outside dev branches of g++ up to 7.2..it's neither standard no mainstream. – Swift - Friday Pie Feb 09 '18 at 21:46

1 Answers1

1

The problem with this code is the member

Barrier task_bar{n_threads};

It is initialized once at the beginning while n_threads is 0. Later, when you call

obj1.num_threads(4);

the barrier object is not updated.

When you update the barrier as well, it works as expected

class Barrier {
public:
// ...
    void num_threads(size_t n) {
        mThreshold = n;
        mCount = n;
    }
// ...
};

and in abc::num_threads()

void num_threads (size_t l) {
    n_threads = l;
    task_bar.num_threads(l);
}
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198