How do I allow a C ++ 11 thread to perform several different functions?

I am learning new multithreading techniques in C ++ 11. Almost all tutorials I read on the internet describe how to start a new thread (or multiple threads) executing a function, how to attach (or detach) a thread (or threads) later, and how to avoid racing conditions with help mutex

etc.

But I don't see any of them showing how to get a thread to do multiple functions in different parts of the program. The question is, with C ++ 11 streams, is it possible to achieve the following? If so, how? (An example would be great.)

void func1(std::vector<int> & data1){ ... }

void func2(std::vector<int> & data2){ ... }

//  main function version I
int main(){
   std::vector<int> data1; 
   // prepare data1 for func1;
   std::thread t1(func1, std::ref(data1));

   std::vector<int> data2; 
   // prepare data2 for func2;
   if (func1 in t1 is done){ 
         t1(func2, std::ref(data2)); 
   }

   t1.join();
   return 0;      
}

      

And further, what if I want to put the specified body main

in a loop like below. Is it possible? If so, how?

//main function version II
int main(){
   std::vector<int> bigdata1;
   std::vector<int> bigdata2;

   std::thread t1; // Can I do this without telling t1 the function 
                   // to be executed?

   for(int i=0; i<10; ++i){
       // main thread prepare small chunk smalldata1 from bigdata1 for func1;

       if(t1 is ready to execute a function){t1(func1, std::ref(smalldata1));}

       // main thread do other stuff, and prepare small chunk smalldata2 from bigdata2 for func2;

       if (func1 in t1 is done){ 
            t1(func2, std::ref(smalldata2)); 
       }
   }

   t1.join();
   return 0;      
}

      

+3


source to share


2 answers


Link from cplusplus.com :

the default constructor creates a thread object that does not represent any thread of execution.

Therefore, it std::thread t

simply does not define the executable thread. When creating a thread, the thread function must be provided and it cannot be installed later.



For your main version of function I, you will need to create two threads. Something like the following:

int main(){
    std::vector<int> data1; 
    // prepare data1 for func1;
    std::thread t1(func1, std::ref(data1));

    std::vector<int> data2; 
    // prepare data2 for func2;
    t1.join(); // this is how you wait till func1 is done

    // you will have to create a new thread here for func2
    std::thread t2(func2, std::ref(data2)); 
    t2.join(); // wait for thread2 (func2) to end

    return 0;      
}

      

Likewise, you can put them in a loop, which is fine, which will give you the main version II function.

+1


source


C ++ 11 threading are primitives designed to enable you to write real libraries. They are not easy to use. You have to wrap them up.

Something like:

struct tasks {
  std::mutex m;
  std::condition_variable v;
  std::vector<std::packaged_task<void>> work;
  std::vector<std::future<void>> finished;
  void operator()(){
    while(true){
      std::packaged_task<void> f;
      {
        std::unique_lock<std::mutex> l(m);
        if (work.empty()){
          v.wait(l,[&]{return !work.empty();});
        }
        f = std::move(work.front());
        work.pop_front();
      }
      if (!f.valid()) return;
      f();
    }
  }
  std::future<void> do(std::function<void()> f){
    std::packaged_task<void> p(f);
    auto r=p.get_future();
    {
      std::unique_lock<std::mutex> l(m);
      work.push_back(std::move(p));
      v.notify_one();
    }
    return r;
  }
  void start(){
    finished.push_back(std::async(std::launch_policy::async,
      std::ref(*this)));
  }
  ~tasks(){
    std::unique_lock<std::mutex> l(m);
    for(auto&&unused:finished){
      work.push_back({});
    }
    v.notify_all();
  }
};

      

usage looks like this:

int main(){
  tasks t;
  t.start();
  t.do([]({std::cout<<"hello ";});
  t.do([]({std::cout<<"world\n";});
}

      



if you want to know when the task is done, check that the future will be returned do

.

Written on the phone, not compiled, possibly filled with typos and errors, but a place to start.

Doesn't support early cancellation. Easy to write abaondon

, which is devastating work

.

Supports multiple consumers (workwe threads) which I suspect. On a compatible system, dtor will wait for all threads to finish jobs in the queue. Not on MSVC2013 tho.

+1


source







All Articles