-1

我有一个程序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;
}

当我运行这个文件时

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

表明

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

我知道它在第 33 行崩溃,函数中的注释行

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");
    }    
}

环境:Boost 版本为 1.54

我的问题是:程序是multiple-read/single-write,如果 MutexClass 已经运行析构函数,在不同的线程中运行 doSomeThing 时如何避免这种情况。
并且只能添加try/catch块?
谢谢!

4

1 回答 1

0

它可以通过很多方式来完成。这里的主要目标不是delete你的对象,直到所有使用它的例程都死了。其中一种方法是使用shared_ptr将对象传递给线程。

看看我在这里做了什么来使这段代码工作。我用 !!! 评论了重大变化

#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;
}
于 2020-12-20T14:13:06.387 回答