我希望有一个线程等待另一个线程破坏特定对象。我想以某种方式实现它:
class Foo {
private:
pthread_mutex_t* mutex;
pthread_cond_t* condition;
public:
Foo(pthread_mutex_t* _mutex, pthread_cond_t* _condition) : mutex(_mutex), condition(_condition) {}
void waitForDestruction(void) {
pthread_mutex_lock(mutex);
pthread_cond_wait(condition,mutex);
pthread_mutex_unlock(mutex);
}
~Foo(void) {
pthread_mutex_lock(mutex);
pthread_cond_signal(condition);
pthread_mutex_unlock(mutex);
}
};
然而,我知道我必须处理waitForDestruction方法中的虚假唤醒,但是我不能在'this'上调用任何东西,因为它已经被破坏了。
我想到的另一种可能性是不使用条件变量,而是在构造函数中锁定互斥锁,在析构函数中解锁它并在waitForDestruction方法中锁定/解锁它 - 这应该适用于非递归互斥锁,和iirc我可以从没有锁定它的线程中解锁互斥锁,对吧?第二种选择会遭受任何虚假的唤醒吗?
答案 0 :(得分:1)
这总是一件困难的事情。但是这些代码行如何:
struct FooSync {
typedef boost::shared_ptr<FooSync> Ptr;
FooSync() : owner(boost::this_thread::get_id()) {
}
void Wait() {
assert(boost::this_thread::get_id() != owner);
mutex.lock();
mutex.unlock();
}
boost::mutex mutex;
boost::thread::id owner;
};
struct Foo {
Foo() { }
~Foo() {
for (size_t i = 0; i < waiters.size(); ++i) {
waiters[i]->mutex.unlock();
}
}
FooSync::Ptr GetSync() {
waiters.push_back(FooSync::Ptr(new FooSync));
waiters.back()->mutex.lock();
return waiters.back();
}
std::vector<FooSync::Ptr> waiters;
};
上面的解决方案将允许单个Foo
对象上的任意数量的销毁等待对象。只要它能正确管理这些对象占用的内存。似乎没有什么能阻止在堆栈上创建Foo
个实例。
虽然我看到的唯一缺点是它需要始终在“拥有”Foo
对象实例的线程中创建destroy-wait对象,否则可能会发生递归锁定。还有更多,如果GetSync
从多个线程调用,则push_back
之后可能会出现竞争条件。
<小时/>
好的,我已经重新考虑了这个问题并提出了新解决方案。看看:
typedef boost::shared_ptr<boost::shared_mutex> MutexPtr;
struct FooSync {
typedef boost::shared_ptr<FooSync> Ptr;
FooSync(MutexPtr const& ptr) : mutex(ptr) {
}
void Wait() {
mutex->lock_shared();
mutex->unlock_shared();
}
MutexPtr mutex;
};
struct Foo {
Foo() : mutex(new boost::shared_mutex) {
mutex->lock();
}
~Foo() {
mutex->unlock();
}
FooSync::Ptr GetSync() {
return FooSync::Ptr(new FooSync(mutex));
}
MutexPtr mutex;
};
现在它似乎相当清洁,而且代码点数远远少于竞争条件。在对象本身和所有同步对象之间只共享一个同步原语。必须采取一些措施来克服在对象本身所在的线程中调用Wait
的情况(如我的第一个示例中所示)。如果目标平台不支持shared_mutex
,则可以使用good-ol mutex
。当shared_mutex
等待很多时,FooSync
似乎减轻了锁的负担。