Reputation: 1
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!
Upvotes: -1
Views: 162
Reputation: 525
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;
}
Upvotes: 0