2

別のスレッドによる特定のオブジェクトの破棄をスレッドに待機させたい。私はそれを次のように実装することを考えました:

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 iロックしていないスレッドからミューテックスをロック解除できますよね?2 番目のオプションは、誤ったウェイクアップの影響を受けますか?

4

1 に答える 1

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;

};

上記の解決策では、1つのFooオブジェクトで任意の数のdestroy-waitオブジェクトを使用できます。これらのオブジェクトが占めるメモリを正しく管理する限り。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;

};

今ではかなりクリーンに見え、コードのポイントが競合状態の影響を受けることははるかに少なくなっています。オブジェクト自体とすべての同期オブジェクトの間で共有される同期プリミティブは1つだけです。Waitオブジェクト自体が存在するスレッドで呼び出された場合(私の最初の例のように)、このケースを克服するためにいくつかの努力を払う必要があります。ターゲットプラットフォームがサポートしていない場合はshared_mutex、good-olを使用してもかまいませんmutex。待機shared_mutexしている人が多い場合は、ロックの負担が軽減されるようです。FooSync

于 2012-06-28T12:08:36.717 に答える