简体   繁体   中英

How to find joinable threads and remove them from vector?

I'm keeping track of some threads in C++ by adding them to a vector.

I want to periodically loop through the vector, check to see if they've exited (they've become joinable), and if so, remove them from the vector.

My code looks like:

void do_stuff(){
    for(int i=0; i<30; i++){
        cout << "Doing Stuff.\n";
        sleep(10);
    }
}

void main_loop(){
    std::vector<std::thread> client_threads;
    while(1){
        if(stuff_needs_to_be_done()){
            client_threads.push_back(std::thread(&do_stuff));
        }

        // Cleanup threads.
        auto itr = std::begin(client_threads);
        while (itr != std::end(client_threads)) {
            if ((*itr).joinable()){
                itr = client_threads.erase(itr);
            }else{
                ++itr;
            }
        }
    }
}

Upon stepping through the code, I find when it gets to my thread cleanup section, my process exits with:

terminate called without an active exception
Aborted (core dumped)

I'm not sure what this means exactly, other than I'm probably not cleaning up my threads correctly. What am I doing wrong?

Use std::promise and std::future::wait_for with zero timeout to indicate the thread exit and wait for non blocking completion (polling) of threads.

The links provide good examples that can be easily adapted for your case.

Using std::async is the easiest way to implement the idea with the vector where you dynamically remove finished threads in the loop. This method is almost the same as @4xy advised, but a little easier.

Anyway, let's avoid the problem XY. Why do you need to remove the elements from the vector? If the only reason is to wait for the last thread to finish, you don't need to remove the elements dynamically. You may query the shared counter (implemented as std::atomic<int> ), and share this variable between threads (or async procedures).

Busy waiting is another problem: why not to stop on a blocking primitive? Logically that is an inverse semaphore , where it is in signaled state whenever the counter is equal to zero. There is no such primitive in current C++ standard, but you can implement it. Recently I've done that using a std::shared_ptr : I'm creating a single shared pointer object and copying it into each of the threads. Each copy is being destroyed whenever the thread finishes. The last one destroys the counter and calls the deleter . The deleter is a custom procedure you may provide. For example it can release a mutex that can be used to block your main thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM