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::jthread
s 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