Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can let a C++11 thread run several different functions?

I am learning the new multi-threading techniques in C++11. Almost all the tutorials I read on the web is teaching how to launch a new thread(or several threads) executing a function, how to join (or detach) the thread(or threads) later and how to avoid racing conditions using mutex, etc.

But I don't see any of them showing how to make a thread execute several functions at different parts of the program. The question is, with C++11 threads, is it possible to achieve the following? If so, how? (Giving an example will 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 the above main function body into a loop, as following. 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;      
}
like image 834
Allanqunzi Avatar asked May 12 '15 00:05

Allanqunzi


People also ask

Can a thread have multiple functions?

Threading allows you to create “threads” that will execute independently of each other. Another way to run multiple functions simultaneously is to use the multiprocessing module, which allows you to create “processes” that will execute independently of each other.

What header file should you include for using C ++ 11 multi threading capabilities?

If you need to execute the operation on a specific instance of the function object, you should use std::ref() from <functional> header to pass your function object by reference.

How do you run a parallel thread in C++?

You actually need to do two things, first create the threads and keep them running(for example do it as pointers) and second call the method join to release all the memory and stuff they needed when they are finished.

What is multi thread in C++?

A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution. Before C++ 11, there is no built-in support for multithreaded applications.


2 Answers

Reference from cplusplus.com:

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

Therefore std::thread t simply doesn't define an executable thread. A thread function has to be provided when creating the thread and it cannot be set afterwards.

For your main function version I, you will have to create two threads. Something as 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;      
}

Similarly, you can put them in a loop and it is alright which will give you main function version II.

like image 80
Yuchen Avatar answered Sep 18 '22 03:09

Yuchen


C++11 threading are primitives intended to allow you to write real libraries. They are not easy to use. You should wrap them.

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();
  }
};

use looks like:

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

if you want to know when a task is done, check the future do returns.

Written on phone, not compiled, probably full of typos and errors, but a place to start.

Does not support abort early. Easy to write abaondon which empties work.

Supports multiple consumers (workwe threads) I suspect. On compliant system, at dtor will wait for all threads to finish the queued jobs. Not on MSVC2013 tho.

like image 41
Yakk - Adam Nevraumont Avatar answered Sep 21 '22 03:09

Yakk - Adam Nevraumont