2

Another SO thread explains how to use thread::native_handle to do things that are outside the C++ threading API (e.g., set the priority of a thread). The gist is:

std::thread t(functionToRun);
auto nh = t.native_handle());
// configure t using nh           

The problem with this approach is that functionToRun may execute for an arbitrary amount of time (including to completion) before the code to configure t is finished.

I believe we can prevent that from happening as follows (untested):

std::atomic<bool> configured(false);

std::thread t([&]{ while (!configured);   // spin until configured is true
                   functionToRun(); });
auto nh = t.native_handle();
// configure t using nh
configured = true;

Unfortunately, this causes the spawned thread to spin waiting for configured to become true. It'd be preferable for the spawned thread to block until configuration is complete.

One way to accomplish that seems to be to use a mutex (also untested):

std::mutex m;

std::unique_lock<std::mutex> lock(m);

std::thread t([&]{ std::lock_guard<std::mutex> lg(m);   // block until m available
                   functionToRun(); });
auto nh = t.native_handle();
// configure t using nh
lock.unlock();                                          // allow t to continue

This seems like it should work, but, conceptually, it seems like a condvar is more suited to the job of indicating when a condition (configuration is complete) is satisfied. But using a condvar requires all of the above, plus a condvar, and it would require dealing with the possibility of spurious wakes, which, as far as I know, is not an issue for mutexes.

Is there a better way to spawn a thread and then have it immediately stop so that I can use its native handle to configure it before allowing it to run further?

Community
  • 1
  • 1
KnowItAllWannabe
  • 12,972
  • 8
  • 50
  • 91
  • 1
    Would it not make more sense to do the waiting in the spawned thread (`functionToRun()`), instead of the spawning one? I.e., have the just-spawned thread go to sleep until signalled "configuration done, proceed" by the spawner? – DevSolar Jun 25 '12 at 05:58
  • 2
    @DevSolar: That's what the code is supposed to do. The spawning thread grabs the mutex, so the spawned thread blocks when it tries to get it. When the spawning thread unlocks the mutex (indicating that configuration is complete), the spawned thread can continue. Note that the spawned function is not functionToRun, it's the lambda-generated closure that calls functionToRun. – KnowItAllWannabe Jun 25 '12 at 06:19

1 Answers1

7

When I wish to delay the start of a thread's main function until some external configuration has been completed I use a future. This avoids the spin-wait, and has the same blocking properties as a mutex or condvar, but provides a clearer intention. Using this pattern, you could write your example as:

std::promise<void> p;
std::thread t([&p]{
    p.get_future().wait();
    thread_func();
}

auto nh=t.native_handle();
// configure nh
p.set_value();

I especially like using this pattern with shared_future for multithreaded tests --- this way you can ensure all threads are running and ready to go before the test begins.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155