0

I'm working on a project where I want to create a thread that branches off the main thread, but does not block it until returned. What I mean by this is that I need the main thread to create the child thread, and the main thread keep working while the child thread goes its separate way (branching off).

I've recreated a smaller-scale version of my code, for simplicity's sake:

#include <iostream>
#include <thread>

using namespace std;

void wait() {
    std::this_thread::sleep_for(std::chrono::duration<int, std::ratio<1,1000>>(200));
}

void one() {
    static int x = 0;
    while(true) {
        cout << "one" << endl;
        wait();
    }
}

void two() {
    while(true) {
        cout << "two" << endl;
        wait();
    }
}

int main() {
    thread t1(one);
    thread t2(two);

    t1.join();
    t2.join();

    cout << "Do stuff beyond here..";

    while(true) {
        cout << "three" << endl;
        wait();
    }

    return 0;
}

My problem is that the threes don't start showing up until after the ones and twos have finished.. Is there any way around this? I've tried omitting the calls to join, but that only crashes the program.

Any help would be greatly appreciated.

Niall
  • 30,036
  • 10
  • 99
  • 142
brads3290
  • 1,926
  • 1
  • 14
  • 20
  • 3
    Don't join your threads until *after* your while-loop. – WhozCraig Jun 05 '15 at 17:14
  • ..which is an infinite loop.. let's just say, it's not the best example – Karoly Horvath Jun 05 '15 at 17:15
  • You should join threads after they have finished there work (or asked to stop), only –  Jun 05 '15 at 17:15
  • @WhozCraig Unfortunately, in the code that I'm creating, that would defeat the purpose. The idea is that an object is created to watch a file for modifications, which starts its own thread to do so. That means that the thread will need to be joined in the FileWatcher::Start (not in the above code) method, or not at all :/ would there be any way to do that? – brads3290 Jun 05 '15 at 17:16
  • 1
    join before the app termination. – Karoly Horvath Jun 05 '15 at 17:17
  • @KarolyHorvath Oh, I know it's an infinite loop. I'm just using it to demonstrate which thread(s) are active. – brads3290 Jun 05 '15 at 17:17
  • 1
    See also: std::thread::detach –  Jun 05 '15 at 17:20
  • 1
    Then presumably the join would go into `FileWatcher::Stop`. The whole point of `join` is to block execution until the child thread is dead. – QuestionC Jun 05 '15 at 17:21

3 Answers3

4

Simplest solution

The first idea that come to my mind would be to postpone the joins:

atomic<bool> finished=false; 

thread t1(one, &finished);  // signature could be changed to inform when finished
thread t2(two, &finished);

// do your processing here, 
while (! finished) 
    // ......

t1.join();
t2.join();

The only restriction is that the tree access must be synchronized, i.e. the main thread shall be aware that things are going on in other threads, and shall avoid race conditions. It shall also be informed when the other threads are finished, for example, using a shared atomic.

Alternative

You could also detach the other threads:

t1.detach(); 
t2.detach(); 
Christophe
  • 68,716
  • 7
  • 72
  • 138
1

From http://www.cplusplus.com/reference/thread/thread/join/

std::thread::join

The function returns when the thread execution has completed.

This synchronizes the moment this function returns with the completion of all the operations in the thread: This blocks the execution of the thread that calls this function until the function called on construction returns (if it hasn't yet).

When you call join, the main thread stops execution and waits for the child thread to complete.

Try moving the joins to the bottom of main().


Also RE:

I've tried omitting the calls to join, but that only crashes the program.

That behavior is explained at https://stackoverflow.com/a/13984169/3294441

calling a thread destructor without first calling join (to wait for it to finish) or detach is guarenteed to immediately call std::terminate and end the program

Community
  • 1
  • 1
QuestionC
  • 10,006
  • 4
  • 26
  • 44
1

The join is required before the thread falls out of scope. Simply allow the threads to be joined as late as possible.

In this case after the loop, just before the main function returns.

If your functions will exit at some unknown point, you could use thread::detach, but that brings with it its own catches.

Niall
  • 30,036
  • 10
  • 99
  • 142