2

次のポリモーフィック インターフェイスがあります。

struct service
{
    virtual void connect(std::function<void>(bool) cb);
      // Invoke 'cb' with 'true' on connection success, 'false' otherwise.

    virtual ~service() { }
};

の一部の実装serviceは同期的です。

struct synchronous_service : service
{
    void connect(std::function<void>(bool) cb) override
    {
        cb(true);
    }
};

その他は非同期です。

struct asynchronous_service : service
{
    void connect(std::function<void>(bool) cb) override
    {
        _thread_pool.post([this, cb]{ cb(true); });
    }
};

serviceそれ自体であるラッパーを作成する必要がありserviceます。これはスレッドセーフである必要があり、以下の状態を維持する必要がありますmutex

struct wrapped_service : service 
{
    state                    _state;
    std::mutex               _mutex;
    std::unique_ptr<service> _underlying;

    void connect(std::function<void>(bool) cb) override
    {
        std::lock_guard<decltype(_mutex)> guard{_mutex};
        // update `_state`

        _underlying->connect([this, cb]
        {
            std::lock_guard<decltype(_mutex)> guard{_mutex};
            // update `_state`
            cb(true);
        });

        // update `_state`
    }
}

_underlying->connect呼び出しが常に非同期である場合は、正常にstd::mutex機能します。ただし、_underlying->connect同期の場合、プログラムはフリーズします。

std::recursive_mutexこれはの代わりにを使用することで解決できますがstd::mutex、一般的にはコード臭であることが知られています。

これは有効な使用例std::recursive_mutexですか?

それとも設計ミス?serviceインターフェイスを制御できないことに注意してください。

4

1 に答える 1