问题
DISCLAIMER: neither Boost, nor C++11 allowed.
I've a program, in which I create an instance of Foo
and I operate with it in a number of threads. Then I want to delete it securely so those threads do not fall into a segmentation fault.
I've added a mutex member to Foo
and lock it each time a thread function runs. In order different threads do not conflict with each other.
class Foo
{
public:
pthread_mutex_t mutex;
};
void* thread ( void* fooPtr )
{
Foo* fooPointer = (Foo*) fooPtr;
while ( 1 )
{
if ( fooPointer )
{
pthread_mutex_lock ( &fooPointer->mutex );
/* some code, involving fooPointer */
pthread_mutex_unlock ( &fooPointer->mutex );
}
else
{
pthread_exit ( NULL );
}
}
}
Now I want to delete foo
securely so no errors occur in threads. I've added a destructor to Foo
:
Foo::~Foo()
{
pthread_mutex_lock ( &mutex );
}
Now the object will not be deleted until all threads finish current loop.
The question is: will the mutex be unlocked after an instance is deleted? Will all the threads finish after an instance is deleted? I bet the answer is no
. So I change the destructor, but now it seems thread-unsafe:
Foo::~Foo()
{
pthread_mutex_lock ( &mutex );
pthread_mutex_unlock ( &mutex );
}
Can the thread function lock the mutex and start operating the instance after pthread_mutex_unlock ( &mutex );
and BEFORE the object is deleted?
回答1:
What is missing here is the condition that dictates when thread processing is completed. Deletion of a particular object instance is not a good condition. You havent shown us where the object is deleted. If we could see this in the code, the extra context would be helpful.
What I would suggest is instead of deleting the object, set a flag on the object (bool active() for example). This flag will then be checked by all threads, and when it indicates stop processing, then the threads will stop. Set this flag where you are currently deleting the Foo object. Then once all threads have stopped, delete the Foo object.
If you delete the object and expect to be able to acquire its mutex lock, you will possibly get a crash, or at the least unstable behavior, since the mutex is a member of Foo, and it will be destroyed with the object.
Here's an example of what I mean:
class Foo
{
public:
void lockMutex();
void unlockMutex();
// Active should be mutex protected as well
// Or you could consider using a pthread_rwlock
bool active() {return active_;}
void setActive(bool a) {active_ = a;}
private:
pthread_mutex_t mutex;
bool active_;
};
void* thread ( void* fooPtr )
{
Foo* fooPointer = (Foo*) fooPtr;
while ( 1 )
{
if ( fooPointer->active() )
{
fooPointer->lockMutex();
/* some code, involving fooPointer */
fooPointer->unlockMutex();
}
else
{
pthread_exit ( NULL );
}
}
// somewhere else in the code
fooPointer->setActive(false);
}
Foo::setActive(true) must be called either in the constructor, or when the object is created. And the Foo object should be deleted once the threads stop, most likely after pthread_join() has completed.
回答2:
Let's start with the begin of your question:
I've a program, in which I create an instance of Foo and I operate with it in a number of threads. Then I want to delete it securely so those threads do not fall into a segmentation fault.
You cannot delete an object which is in use. No amount of mutexes will fix that.
I've added a destructor to Foo
This is only run when Foo
is being deleted. Its contents don't matter much, though: It's wrong to call the dtor while other threads are still using Foo.
I want a thread securely exit when an instance is deleted. How is it possible?
Well, that's the correct question. I could write a whole lot of code for you to use, but that code would just be a copy of boost::weak_ptr
. So, I won't bother. Just take the boost code yourself.
Boost not allowed.
Then why are you asking on StackOverflow? That's essentially the same license.
回答3:
your code posted is not right because c++ object is destroyed by steps blow:
obj->Foo::~Foo();
free memory //maybe delete if allocated by new
so your source is only protoecting the destructor but not the memory free itself.
maybe source code follows could help you, it's simple and crude but I think it can works
class Foo
{
public:
void dosomething() {}
};
template<typename T>
class Protect
{
public:
struct auto_lock {
auto_lock(pthread_mutex_t& mutex)
: _mutex(mutex)
{
pthread_mutex_lock ( &_mutex );
}
~ auto_lock()
{
pthread_mutex_unlock ( &_mutex );
}
pthread_mutex_t& _mutex;
};
Protect(T*& p): _p(p) {}
T* get() { return _p; }
void lock() { pthread_mutex_lock ( &_mutex ); }
void unlock() { pthread_mutex_unlock ( &_mutex );}
pthread_mutex_t& getlock() { return _mutex; }
void safe_release() {
auto_lock l(_mutex);
if (_p != NULL) {
delete _p;
_p = NULL;
}
}
private:
T*& _p;
pthread_mutex_t _mutex;
};
void* thread ( void* proPtr )
{
Protect<Foo>* proPointer = (Protect<Foo>*) proPtr;
while ( 1 )
{
Protect<Foo>::auto_lock l(proPointer->getlock());
Foo* fooPtr = proPointer->get();
if ( fooPtr )
{
fooPtr->dosomething();
}
else
{
pthread_exit ( NULL );
}
}
}
来源:https://stackoverflow.com/questions/12455297/delete-an-object-securely-from-a-multi-threaded-program