如何让线程等待对象的销毁

how to let a thread wait for destruction of an object

本文关键字:对象 等待 线程      更新时间:2023-10-16

我想让一个线程等待另一个线程销毁特定对象。我想过以某种方式实现它,就像这样:

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 我可以从未锁定它的线程解锁互斥锁,对吧?第二个选项会受到任何虚假唤醒的影响吗?

这总是一件困难的事情。但是这些代码行怎么样:

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线程中创建,否则可能会发生递归锁。还有更多,如果从多个线程调用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则可以使用好的mutexshared_mutex似乎减轻了锁的负担,因为有很多FooSync在等待。