c++multithreadingparallel-processingcollaborative

C++, Running two functions in parallel and collaborative way


I have two methods that I want to execute in parallel, data are passed by const reference.

As soon as one of the method has finished its job, it is not necessary for the other to continue, since one of them can have a long execution time depending the entry and therefore must stop.

I found that I could execute the two methods in parallel by running two threads using the <thread> header, but i had to wait for both methods to finish after joining them.

How can i achieve this type of parallel processing with such a collaborative mecanisme ?.


Solution

  • I wrote a small sample to show how it is done. It is not archivable with join, as you already found out. You need an event you can signal from a thread, when it has the result. For that, you have to use std::conditon_variable. The sample shows the minimal possible solution for your described problem. In the sample, the result is a simple in.

    There are two pitfalls you have to care.

    a.The thread is finished before the main is waiting for. For that reason I lock the mutex before I start the threads.

    b. The result is overwritten. I managed that by testing the result before writing it.

    #include <thread>
    #include <condition_variable>
    #include <mutex>
    
    std::mutex mtx;
    std::condition_variable cv;
    
    int result = -1;
    
    void thread1()
    {
        // Do something
        // ....
        // ....
    
        // got a result? publish it!
        std::unique_lock<std::mutex> lck(mtx);
        if (result != -1)
            return; // there is already a result!
    
        result = 0; // my result
        cv.notify_one(); // say I am ready
    }
    
    void thread2()
    {
        // Do something else
        // ....
        // ....
    
        // got a result? publish it!
        std::unique_lock<std::mutex> lck(mtx);
        if (result != -1)
            return; // there is already a result!
    
        result = 1; // my result
        cv.notify_one(); // say I am ready
    }
    
    int main(int argc, char * argv[])
    {
        std::unique_lock<std::mutex> lck(mtx); // needed so the threads cannot finish befor wait
        std::thread t1(thread1), t2(thread2);
    
        cv.wait(lck); // wait until one result
    
        // here result is 0 or 1;
    
        // If you use the loop described below, you can use join safely:
        t1.join();
        t2.join();
        // You have to call join or detach of std::thread objects before the
        // destructor of std::thread is called. 
    
        return 0;
    }
    

    If you want to stop the other thread if one has already a result, the only legit way is to test the result frequently in both threads an stop if someone already has the result. In this case, if you use a pointer or or generic type, you should mark it with the volatile modifier. Here how the thread function may look if you have to do work in a loop:

    void thread1()
    {
        // Do something
        bool bFinished=false;
        while(!bFinished)
        {
          { // this bracket is necessary to lock only the result test. Otherwise you got a deadlock a forced sync situation.
            std::unique_lock<std::mutex> lck(mtx);
            if (result != -1)
               return; // there is already a result!
          }         
          // do what ever you have to do
        }
    
        // got a result? publish it!
        std::unique_lock<std::mutex> lck(mtx);
        if (result != -1)
            return; // there is already a result!
    
        result = 0; // my result
        cv.notify_one(); // say I am ready
    }