Home > OS >  Error nested std::thread inside a thread throws an error
Error nested std::thread inside a thread throws an error

Time:02-10

I'm trying to get this simple test to create a nested thread inside another thread, but it keeps failing. Tried removing this nested function and the code works fine on its own.

Code example/test:

#include <thread>
#include <iostream>
#include <vector>

void simple() {  std::cout << "\nNested Thread";  }

void function(int number, int* sum, std::vector<std::thread>& thread_group) {
    *sum  = number;

    // Starting this nested function simple() in a thread causes errors.
    // The problem occurs even when there's only a single iteration of the loop.
    // Without it the code works fine, even with 10000 iterations.
    std::thread ct(simple);
    thread_group.push_back(std::move(ct));
}

int main(){
    // Container for storing threads
    std::vector<std::thread> thread_group;
    int sum = 0;
    for (int n = 1; n <= 10; n  ) {
        std::thread t(function, n, &sum, std::ref(r), std::ref(thread_group));
        // Add the newly created thread to the container
        thread_group.push_back(std::move(t));
    }
    // Wait for all threads to finish
    join_all(thread_group);
    return 0;
}

That being said, I need to find a way call an independent function that could run without blocking the execution of the rest of the code. Threading or some other way of multiprocessing is very important in my program because each function is recursive and keeps calling multiple copies of itself with different parameters untill a condition is satisfied.

I don't know whether it's even possible in the std::thread library. Tried using Poco and boost, but was faced with other problems, so decided to stick to std::thread instead.

I'm using Visual Studio 2022 on Windows 10.

CodePudding user response:

You are reading and writing to sum and thread_group from multiple threads at the same time. A simple solution is you make sure that only one thread at a time has access to them by using a std::mutex and locking it while accessing those variables. You also need to make sure that all threads are finished working with thread_group before it gets destroyed. I added a counter and a std::condition_variable to take care of that.

Example (using C 20 std::jthreads instead to not have to call the non-existing join_all function):

#include <condition_variable>
#include <iostream>
#include <list>     // using list instead of vector to avoid realloc
#include <mutex>
#include <thread>
#include <vector>

using container = std::list<std::jthread>;

void simple() {  std::cout << "Nested Thread\n";  }

void function(int& counter, std::mutex& mtx,
              std::condition_variable& cv, container& thread_group)
{
    std::lock_guard lock(mtx);
    thread_group.emplace_back(simple);
      counter;       // so that main thread can check that all is done
    cv.notify_one(); // signal main that the work is done
}

int main(){
    // Container for storing threads
    container thread_group;
    std::mutex mtx;
    std::condition_variable cv;

    int starting_threads = 10;
    int counter = 0;
    for (int n = 1; n <= starting_threads; n  ) {
        std::lock_guard lock(mtx); // lock while adding thread
        // Add thread to the container
        thread_group.emplace_back(function, std::ref(counter), std::ref(mtx),
                                  std::ref(cv), std::ref(thread_group));
    }   
    
    std::unique_lock lock(mtx);
    // wait until all threads are done with thread_group
    // before letting thread_group go out of scope and get
    // destroyed
    while(counter < starting_threads) cv.wait(lock);

    std::cout << thread_group.size() << '\n';

    // wait for all threads to finish (jthread's auto-join)
}

Possible output:

Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
Nested Thread
20
Nested Thread
  • Related