C++ multithread joining only working on the first thread but not working for other threads
I was curious as to why the code below works and executes fine for the n = 1
case, but when I make n
anything greater than 1
I get a system error most of the time.
I also know there is joinable()
for checking if a thread is done but it is terrible since it blocks the main thread. If there is a more elegant solution to checking when a thread is done than passing a boolean pointer to a method, that would be appreciated.
#include <iostream>
#include <thread>
#include <atomic>
#include <array>
void my_function(bool* is_thread_done) {
std::cout << "Thread started" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Thread finished" << std::endl;
*is_thread_done = true;
}
int main() {
const int n = 1;
std::array<std::thread, n> arr;
std::array<bool, n> is_thread_done;
for (int i = 0; i < n; i++) {
is_thread_done[i] = false;
arr[i] = std::thread(my_function, &is_thread_done[i]);
}
int all_done = 0;
while (all_done < n) {
for (int i = 0; i < n; i++) {
if (is_thread_done[i]) {
arr[i].join();
all_done++;
}
}
}
return 0;
}
I have tried joinable but that is not useful because of blocking.
To answer the comments:
- The order that I join the threads doesn't matter, but a loop is just the way I'm doing it.
- I cannot join the thread before its done because it will block the main thread. I simplified this code from my actual use for it and I cannot have the main thread be blocked. This is the general premise though. That is why I also cannot use
joinable()
to join. - I have tried
atomic<bool>
and it did not seem to have any effect. I don't know why this would matter though however since by the time the boolean becomes set totrue
, the thread would be done.
Here is the code form the thread pool I was making. n
threads working on some task k times. Since k
is greater than n
, when a thread finishes, a new thread is dispatched to continue working on the task. The main thread needs to dispatch another thread immediately, not wait for n
thread to finish and then dispatch another thread. In that case its acting like a barrier which I don't need.
template<typename Func, typename... Args>
void ThreadPool::thread_pool_executor(Func func, Args... args) {
while (running) {
while (free_indecies.size() > 0 && running) {
int i = free_indecies.front();
pool[i] = std::make_unique<std::thread>(
&ThreadPool::worker<Func, Args...>, this,
&avalability[i], func, args...);
free_indecies.pop();
avalability[i] = false;
current_iter++;
if (current_iter == total_iter) running = false;
}
for (int i = 0; i < max_threads; i++) {
if (avalability[i]) {
pool[i]->join();
free_indecies.push(i);
}
}
}
for (int i = 0; i < max_threads; i++) {
if (pool[i]->joinable()) {
pool[i]->join();
}
}
reset();
}
template<typename Func, typename... Args>
void ThreadPool::worker(std::atomic<bool>* complete, Func func, Args... args) {
std::invoke(func, args...);
*complete = true;
}
I realized what Ben was saying and changed the loop in the first code segment to the following and now that simpler example works. I created a set and initialized it to hold the numbers 1-n initially.
while (not_done.size() > 0) {
for (int i : not_done) {
if (is_thread_done[i]) {
arr[i].join();
not_done.erase(i);
}
}
}
I also realized that in the threadpool example where I am trying to apply this idea, I should have had availability[i] = false
right before I make the thread to avoid a race condition. However the code from that case still has the thread::join failed: Invalid argument Abort trap: 6
error
Comments
Post a Comment