Delayed start of a thread in C++ 11

C++MultithreadingC++11

C++ Problem Overview


I'm getting into C++11 threads and have run into a problem.

I want to declare a thread variable as global and start it later.

However all the examples I've seen seem to start the thread immediately for example

thread t(doSomething);

What I want is

thread t;

and start the thread later.

What I've tried is

if(!isThreadRunning)
{
	thread t(readTable);
}

but now t is block scope. So I want to declare t and then start the thread later so that t is accessible to other functions.

Thanks for any help.

C++ Solutions


Solution 1 - C++

std::thread's default constructor instantiates a std::thread without starting or representing any actual thread.

std::thread t;

The assignment operator moves the state of a thread object, and sets the assigned-from thread object to its default-initialized state:

t = std::thread(/* new thread code goes here */);

This first constructs a temporary thread object representing a new thread, transfers the new thread representation into the existing thread object that has a default state, and sets the temporary thread object's state to the default state that does not represent any running thread. Then the temporary thread object is destroyed, doing nothing.

Here's an example:

#include <iostream>
#include <thread>

void thread_func(const int i) {
    std::cout << "hello from thread: " << i << std::endl;
}

int main() {
    std::thread t;
    std::cout << "t exists" << std::endl;
    
    t = std::thread{ thread_func, 7 };
    t.join();
    
    std::cout << "done!" << std::endl;
}

Solution 2 - C++

I would give the thread a condition variable and a boolean called startRunning (initially set to false). Effectively you would start the thread immediately upon creation, but the first thing it would do is suspend itself (using the condition_variable) and then only begin processing its actual task when the condition_variable is signaled from outside (and the startRunning flag set to true).

EDIT: PSEUDO CODE:

// in your worker thread
{
    lock_guard l( theMutex );

    while ( ! startRunning )
    {
        cond_var.wait( l );
    }
}

// now start processing task


// in your main thread (after creating the worker thread)
{
    lock_guard l( theMutex );
    startRunning = true;
    cond_var.signal_one();
}

EDIT #2: In the above code, the variables theMutex, startRunning and cond_var must be accessible by both threads. Whether you achieve that by making them globals or by encapsulating them in a struct / class instance is up to you.

Solution 3 - C++

There is no "standard" of creating a thread "suspended" which I assume is what you wanted to do with the C++ thread library. Because it is not supported on every platform that has threads, it is not there in the C++ API.

  1. You might want to create a class with all the data it is required but not actually run your thread function. This is not the same as creating the thread but may be what you want. If so, create that, then later bind the object and its operator() or start() function or whatever to the thread.

  2. You might want the thread id for your thread. That means you do actually need to start the thread function. However it can start by waiting on a condition variable. You then signal or broadcast to that condition variable later when you want it to continue running. Of course you can have the function check a condition after it resumes in case you might have decided to close it and not run it after all (in which case it will just return instantly).

  3. You might want a std::thread object with no function. You can do that and attach it to a function later to run that function in a new thread.

Solution 4 - C++

first declared in class m_grabber runs nothing. We assign member class object with new one with lambda function in launch_grabber method and thread with lambda runs within source class context.

class  source {
...
 std::thread m_grabber;
 bool m_active;
...
}

    
bool source::launch_grabber() {
	// start grabber
	m_grabber = std::thread{ 
		[&] () {
			m_active = true;
			while (true)
			{
				if(!m_active)
					break;
                // TODO: something in new thread

			}
		}
	};

	m_grabber.detach();
	return true;
}

Solution 5 - C++

As antred says in his answer, you can use a condition variable to make the thread to wait in the beginning of its routine.

Scott Meyers in his book “Effective Modern C++” (in the “Item 39: Consider void futures for one-shot event communication”) proposes to use void-future instead of lower level entities (boolean flag, conditional variable and mutex). So the problem can be solved like this:

auto thread_starter = std::promise<void>;
auto thread = std::thread([starter_future = thread_starter.get_future()]() mutable {
    starter_future.wait(); //wait before starting actual work
    …; //do actual work
});
…; //you can do something, thread is like “paused” here
thread_starter.set_value(); //“start” the thread (break its initial waiting)

Scott Meyers also warns about exceptions in the second (marked by the you can do something, thread is like “paused” here comment). If thread_starter.set_value() is never called for some reasons (for example, due to exception throws in the second ), the thread will wait forever, and any attempt to join it would result in deadlock.

As both ways (condvar-based and future-based) contain hidden unsafety, and the first way (condvar-based) needs some boilerplate code, I propose to write a wrapper class around std::thread. Its interface should be similar to the one of std::thread (except that its instances should be assignable from other instances of the same class, not from std::thread), but contain additional void start() method.

Future-based thread-wrapper

class initially_suspended_thread {
    std::promise<bool> starter;
    std::thread impl;
public:
    template<class F, class ...Args>
    explicit initially_suspended_thread(F &&f, Args &&...args):
        starter(),
        impl([
            starter_future = starter.get_future(),
            routine = std::bind(std::forward<F>(f), std::forward<Args>(args)...)
        ]() mutable {if (starter_future.get()) routine();})
    {}
    void start() {starter.set_value(true);}
    ~initially_suspended_thread() {
        try {starter.set_value(false);}
        catch (const std::future_error &exc) {
            if (exc.code() != std::future_errc::promise_already_satisfied) throw;
            return; //already “started”, no need to do anything
        }
        impl.join(); //auto-join not-yet-“started” threads
    }
    …; //other methods, trivial
};

Condvar-based thread-wrapper

class initially_suspended_thread {
    std::mutex state_mutex;
    enum {INITIAL, STARTED, ABORTED} state;
    std::condition_variable state_condvar;
    std::thread impl;
public:
    template<class F, class ...Args>
    explicit initially_suspended_thread(F &&f, Args &&...args):
        state_mutex(), state(INITIAL), state_condvar(),
        impl([
            &state_mutex = state_mutex, &state = state, &state_condvar = state_condvar,
            routine = std::bind(std::forward<F>(f), std::forward<Args>(args)...)
        ]() {
            {
                std::unique_lock state_mutex_lock(state_mutex);
                state_condvar.wait(
                    state_mutex_lock,
                    [&state]() {return state != INITIAL;}
                );
            }
            if (state == STARTED) routine();
        })
    {}
    void start() {
        {
            std::lock_guard state_mutex_lock(state_mutex);
            state = STARTED;
        }
        state_condvar.notify_one();
    }
    ~initially_suspended_thread() {
        {
            std::lock_guard state_mutex_lock(state_mutex);
            if (state == STARTED) return; //already “started”, no need to do anything
            state = ABORTED;
        }
        impl.join(); //auto-join not-yet-“started” threads
    }
    …; //other methods, trivial
};

Solution 6 - C++

You could use singleton pattern. Or I would rather say antipattern.

Inside a singleton you would have std::thread object encapsulated. Upon first access to singleton your thread will be created and started.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSmithyView Question on Stackoverflow
Solution 1 - C++Sam VarshavchikView Answer on Stackoverflow
Solution 2 - C++antredView Answer on Stackoverflow
Solution 3 - C++CashCowView Answer on Stackoverflow
Solution 4 - C++IgorView Answer on Stackoverflow
Solution 5 - C++SashaView Answer on Stackoverflow
Solution 6 - C++GreenScapeView Answer on Stackoverflow