0

I am completely begginner in C++ and threads as well. I have made a very simple example of my problem. In the code I provide, I create threads and detach them. Each thread executes a different function: one which consists in pushing an int into a queue, and the other one reads that value and simulate a long processing with the read value and the function's argument. The queue object is protected by a mutex as it is shared between the two threads. I know that my code is a bit stupid but I have made it to represent my real problem, which uses detached threads and a shared queue protected by mutex.

Here's the code:

#include <mutex>
#include <iostream>
#include <thread>
#include <queue>    
using namespace std;      

std::queue<int> tasks;
std::mutex m; 

void push_task(int arg) {

    printf("[Pushing task into the queue]");

    m.lock();
    tasks.push(arg);
    m.unlock();

}

void process_task(int number) {

    printf("[Processing task from the queue]");

    m.lock();

    while (tasks.empty() == false){

        int task = tasks.front(); 
        tasks.pop(); 
        printf("[Processing...]");
        std::this_thread::sleep_for(std::chrono::milliseconds((task+number)*1000)); //simulate some execution
        printf("[Task has been successfully processed]");
    }

    m.unlock(); 
}

int launch_threads(int nTask, int n){

    int counter = 0;

    while(counter < 8){
        std::thread(push_task, nTask).detach();
        std::thread(process_task, n).detach();
        counter++;
    }

    printf("[Launch Threads Ends]");

    return 0;
}

int main(){

   launch_threads(0, 10000);

    printf("[Main Ends]");

    return 0;

}

Well, the problem I am facing is that I got the following error:

mutex destroyed while busy

I have investigate and I have read (correct me if I am wrong) that this happens because the calling function, in my case launch_threads(), ends while the local threads created inside it are still running and therefore the mutex can still be owned by some thread (is busy), giving that error. In fact, no processing inside the threads really ends.

My question is: How can I avoid that error?

I have also read that not making the threads as local variables may solve the problem. In that case, how can I declare the threads as global, if I am passing a function with an argument to them?

Extra question related to the topic: May using std::lock_guard lock(m) help to avoid the problem?

Thank you in advance!

anaVC94
  • 3
  • 4
  • 2
    I would recommend to read this question: [What happens to a detached thread when main() exits?](https://stackoverflow.com/q/19744250/580083). – Daniel Langr Sep 25 '19 at 11:15
  • Don't detach the threads. Join them. `detach()` should not be in your toolkit when you're just getting started with threads. – Pete Becker Sep 25 '19 at 13:00

2 Answers2

3

You launch some threads and detach them. Then you let the main function return which terminates the process. That process termination kills all threads and also causes all global objects to be destructed.

You should only exit the thread that the main function is running in, which lets the detached threads continue running in the process (which then exits when the last thread have exited).

There's currently no way to exit a thread in the C++ standard library, so you have to use system-dependent functions. For example in POSIX systems (like Linux or macOS) you use the pthread_exit function.


There are of course two other possible solutions:

  1. Don't detach the threads, and join them before exiting from main. This might not always be possible or desired though.

  2. Wait inside the main function for the detached threads to exit, using some other kind of waiting or polling mechanism that the threads have exited. This might also not be desired. And could be problematic if the threads set a flag inside the threads themselves that the main function checks, which might lead to a race condition where the thread haven't actually exited before the main function returns.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thank you, I really appreciate it – anaVC94 Sep 25 '19 at 12:25
  • Re, "You should do X... There's no standard way to do X, so you'll have to use system-dependent functions." That might be good advice if doing X was the only way to solve some problem, but that's not the case here. The OP does not _need_ the main thread to terminate before the other threads. The program would work just as well if the OP re-wrote it so that the main thread would `join()` the threads that it created. – Solomon Slow Sep 25 '19 at 13:20
  • @SolomonSlow Except that detached threads can't be joined. And there are plenty of use-cases where one could want detached threads that continue to work even though the main thread exits. – Some programmer dude Sep 25 '19 at 13:22
  • Sorry, I assumed that it was well known that a C++ program must make _exactly one_ call to either `t.detach()` or `t.join()` on every `std::thread t`. Bad assumption. I guess should have said, "The program would work just as well if the OP re-wrote it so that the main thread would join() each of the threads that it created _instead of detach()ing them._" – Solomon Slow Sep 25 '19 at 13:27
2

Your main function ends - and so does your whole program. Any other threads can't stop this - so you have to wait for them to finish (see std::thread::join). That is probably all you need. But whats with mutex? All program resources are destroyed at the end of a program - and you can't destroy busy mutex (see std::lock_guard)

Update: noticed another bad thing - you didn't synchronize threads - so producing/consuming threads will have data race and it is not guaranteed that all your data is processed.

Xellos
  • 153
  • 4