Search code examples
c++multithreadingboostreadwritelockboost-exception

Boost multithreading exception


I have a program like main.cpp

#include <stdio.h>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread.hpp>

class MutexClass
{
private:
    /* data */
    boost::shared_mutex m_mutex;
    bool running;   //The flag program should stop
public:
    MutexClass(/* args */);
    ~MutexClass();
    void doSomeThing();
};

MutexClass::MutexClass(/* args */)
{
    running = true;
    printf("MutexClass()\n");
}

MutexClass::~MutexClass()
{
    printf("~MutexClass\n");
    boost::unique_lock<boost::shared_mutex> lock(m_mutex);
    running = false;
}

void MutexClass::doSomeThing() {
    printf("doSomeThing\n");  //In fact, here is a callback or loop

    boost::shared_lock<boost::shared_mutex> lock(m_mutex); //(1)Exception here
    if(running){
        printf("still running!\n");
    }    
}

void doSomeThing(MutexClass* mtx) {
    sleep(3);
    mtx->doSomeThing();
}

void destroy(MutexClass* mtx) {
    sleep(2);
    delete mtx;
    mtx = NULL;
}


int main(int argc, char* argv[])
{
    MutexClass* mtx = new MutexClass();
    boost::thread thrd1(&doSomeThing,mtx);
    boost::thread thrd2(&destroy,mtx);
    thrd1.join();
    thrd2.join();
    sleep(5);
    return 0;
}

when I run this file with

g++ main.cpp -lboost_system -lboost_thread -g -o main && ./main

It shows

MutexClass()
~MutexClass
doSomeThing
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
  what():  boost: mutex lock failed in pthread_mutex_lock: Invalid argument
Aborted

I know it crash at line 33, the comment line in the function

void MutexClass::doSomeThing() {
    printf("doSomeThing\n");  //In fact, here is a callback or loop

    boost::shared_lock<boost::shared_mutex> lock(m_mutex); //Exception here
    if(running){
        printf("still running!\n");
    }    
}

Env: Boost Version is 1.54

My question is: The program is multiple-read/single-write, how can I avoid this when run doSomeThing in a different thread, if the MutexClass already run destructor.
And only can add try/catch block?
Thanks!


Solution

  • It can be done by plenty of ways. The main goal here is not to delete your object until all the routines using it are dead. One of the method is using shared_ptr to pass the object into thread.

    Take a look at what I'd done here to make this code work. I've commented the significant changes with !!!

    #include <stdio.h>
    #include <boost/thread/shared_mutex.hpp>
    #include <boost/thread.hpp>
    #include <thread>
    
    class MutexClass
    {
    private:
        /* data */
        boost::shared_mutex m_mutex;
        bool running;   //The flag program should stop
    public:
        MutexClass(/* args */);
        ~MutexClass();
        void doSomeThing();
        void stop() {       // !!! changing running to false moves to this method
            printf("stop()\n");
            boost::unique_lock<boost::shared_mutex> lock(m_mutex);
            running = false;
        }   
    };
    
    MutexClass::MutexClass(/* args */)
    {
        running = true;
        printf("MutexClass()\n");
    }
    
    MutexClass::~MutexClass()
    {
        printf("~MutexClass\n");
    }
    
    void MutexClass::doSomeThing() {
        printf("doSomeThing\n");  //In fact, here is a callback or loop
    
        boost::shared_lock<boost::shared_mutex> lock(m_mutex); //(1)Exception here
        if (running) {
            printf("still running!\n");
        }
        else {
            printf("not running!\n");
        }
    }
    
    void doSomeThing(std::shared_ptr<MutexClass> mtx) {
        std::this_thread::sleep_for(std::chrono::seconds(3));
        mtx->doSomeThing();
    }
    
    void destroy(std::shared_ptr<MutexClass> mtx) {
        std::this_thread::sleep_for(std::chrono::seconds(2));
    
        mtx->stop();        // !!! Stop instead of delete
    }
    
    
    int main(int argc, char* argv[])
    {
        auto mtx = std::make_shared<MutexClass>();  // !!! store mtx in shared ptr
        boost::thread thrd1(&doSomeThing, mtx);
        boost::thread thrd2(&destroy, std::move(mtx));  // !!! You can play with std::move here to see where your object is destroyed.
        thrd1.join();
        thrd2.join();
        printf("after join\n");     // before this line mtx object should be destroyed
        std::this_thread::sleep_for(std::chrono::seconds(5));
        //sleep(5);
        return 0;
    }