1

I want to keep my code clean and do the things right, to any std::thread I need to do join or detach, but how can I wait (at the main thread) for another thread without blocking the execution of the main thread?

void do_computation()
{
    //  Calculate 1000 digits of Pi.
}


int main()
{
    std::thread td1(&do_computation);

    while (running)
    {
        //  Check if thread td1 finish and if yes print a message

        //  Here are some stuff of the main to do...
        //  Print to UI, update timer etc..

    }

    //  If the thread has not finished yet here, just kill it.
}
Ron
  • 511
  • 1
  • 5
  • 14
  • 1
    If, as you confess, you can communicate with the thread to see if it finished, communicate in reverse and tell it to stop... – StoryTeller - Unslander Monica Jan 01 '19 at 10:09
  • The only way a thread can "wait" for another is by blocking. Those words are synonymous in this context, so it's not clear what exactly do you want to achieve. Or do you want to stop the thread instead of waiting for it? – r3mus n0x Jan 01 '19 at 10:28
  • @Ron - what you mean under "not to block" ? – RbMm Jan 01 '19 at 10:35
  • I want to check if a thread has been finished, but not to block the checker thread. As i see that can be achieved using mutex/semaphore that the worker thread will set and the main thread will check, this seems to be a good idea. **But** what if I got an exception at the worker thread? As i see in this case the mutex will never set, so i will just want to do join in order to clean any resource and continue with execution of the main. How can I achieve that? – Ron Jan 01 '19 at 10:43
  • *but not to block the checker thread* - what you mean under this, what is checker thread doing else ? – RbMm Jan 01 '19 at 10:48
  • @RbMm - I mean that instead of 'wait' to the thread I want to check, 'is the thread already finished?' and to get an answer, true or false immediately, but not to 'stuck' on that line. (also, if I got true, I will call to join in order to clean any resource and print a message to screen) – Ron Jan 01 '19 at 10:52
  • @RbMm - The checker is the main thread, and need to print/read to/from UI, update some timer counters, etc.. – Ron Jan 01 '19 at 10:57
  • @Ron - but what is your thread (from which you want to check) doing ? answer depend from this and concrete os. no general answer. if say this is windows and you have gui thread(which process user input) you need use `MsgWaitForMultipleObjectsEx` for wait for user input and thread exit at once. if your thread not wait for user input, but do another things - question - which concrete ? no general answer – RbMm Jan 01 '19 at 10:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/186005/discussion-between-ron-and-rbmm). – Ron Jan 01 '19 at 11:01

2 Answers2

1

The answer is semaphores. You can use a binary semaphore to synchronize your threads.

You may use System V semaphores or pthread mutexes, but they are somehow legacy in C++. Using Tsuneo Yoshioka's answer, we could implement a C++ way of semaphore, though.

#include <mutex>
#include <condition_variable>

class Semaphore {
public:
    Semaphore (int count_ = 0)
        : count(count_) {}

    inline void notify()
    {
        std::unique_lock<std::mutex> lock(mtx);
        count++;
        cv.notify_one();
    }

    inline void wait()
    {
        std::unique_lock<std::mutex> lock(mtx);

        while(count == 0){
            cv.wait(lock);
        }
        count--;
    }

private:
    std::mutex mtx;
    std::condition_variable cv;
    int count;
};

Your implementation may make use of the Semaphore class, like so.

void do_computation()
{
    //calculate 1000 digits of Pi.

    semaphore.notify();
}


int main()
{
    Semaphore semaphore(0);
    std::thread td1(&do_computation);

    semaphore.wait();
}
Buğra Ekuklu
  • 3,049
  • 2
  • 17
  • 28
  • As i see the line `semaphore.wait();` is blocking. Am I right? – Ron Jan 01 '19 at 10:30
  • I actually thought you were asking for a solution without busy waiting. You may use a `try_wait` implementation to do that, or moreover, head over to `std::promise` and `std::future`. – Buğra Ekuklu Jan 01 '19 at 10:48
-2

You can use std::promise and std::future. More info here and here.

#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

void accumulate(std::vector<int>::iterator first,
                std::vector<int>::iterator last,
                std::promise<int> accumulate_promise)
{
    int sum = std::accumulate(first, last, 0);
    accumulate_promise.set_value(sum);  // Notify future
}

void do_work(std::promise<void> barrier)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    barrier.set_value();
}

int main()
{
    // Demonstrate using promise<int> to transmit a result between threads.
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };
    std::promise<int> accumulate_promise;
    std::future<int> accumulate_future = accumulate_promise.get_future();
    std::thread work_thread(accumulate, numbers.begin(), numbers.end(),
                            std::move(accumulate_promise));
    accumulate_future.wait();  // wait for result
    std::cout << "result=" << accumulate_future.get() << '\n';
    work_thread.join();  // wait for thread completion

    // Demonstrate using promise<void> to signal state between threads.
    std::promise<void> barrier;
    std::future<void> barrier_future = barrier.get_future();
    std::thread new_work_thread(do_work, std::move(barrier));
    barrier_future.wait();
    new_work_thread.join();
}
Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78