2023-03-28

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:

  1. The order that I join the threads doesn't matter, but a loop is just the way I'm doing it.
  2. 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.
  3. 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 to true, 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



No comments:

Post a Comment