1

私は問題があります。プログラムでミューテックスを使用したい。何が起こるかというと、std::timed_mutex を保持するオブジェクトを作成しています。このオブジェクトは作成時にミューテックスをロックします。後でロックを解除する必要があるためです。ミューテックスを作成した同じスレッドは、他のスレッドがバックグラウンドで動作している間、そのミューテックスを待機する必要があります。スレッドに参加することはオプションではありません。

class A{
    std::timed_mutex mutex;
    A(){
        mutex.lock();
    }

    bool waitForIt(int timeout){
        if(mutex.try_lock_for(std::chrono::milliseconds(timeout))){
            mutex.unlock();
            return true;
        }else{
            return false;
        }
    }
}

同じスレッドから waitForIt を呼び出すと、プログラムは通過し、タイムアウトを完全に無視して即座に false を取得します (はい、後でミューテックスのロックを解除することを目的としています。待機中のすべてのスレッドが通過するように、イベントのようなものを模倣する必要があります)。

そのため、ドキュメントでは、このミューテックスには非再帰的な動作があると書かれています。しかし、テストにより、たとえば、ブロックされることなく同じスレッドから .lock() を複数回使用できることが明らかになりました。また、try_lock_for を複数回使用して、毎回 true にすることもできます!!! try_lock_fors の前に一度ロックを使用すると、常に false になります。悲しいことに、ミューテックスをロックした同じスレッドもブロックするものが必要です。そして、私は何を使うべきかわかりません。ところで、Linuxでプログラミングしています。ネイティブソリューションがあるかもしれませんか?

また、std libs にセマフォが見つかりませんでした。ミューテックスの代わりにそれを使用できます。独自の実装を使用することは可能ですが、独自のセマフォを作成する方法がわかりません。何か案は?

人々はそれほど単純ではないことを理解していないようです:

class IObservable : public IInterface{
private:
    std::list<std::shared_ptr<IObserver>> observers;
public:
    virtual ~IObservable(){}

    void AddObserver(std::shared_ptr<IObserver> observer);
    void RemoveObserver(std::shared_ptr<IObserver> observer);
    void ClearObservers();
    void TellCompleted(bool wasCanceled = false, std::shared_ptr<void> status = 0);
    TYPEIDHASHFUNC(IObservable)
};

IObservable は、スレッドがオブザーバーを追加できるものです。IObservable から派生したものは、そのアクションの最後にメソッド TellCompleted を呼び出します。

class IObserver : public IInterface{
public:
    virtual ~IObserver(){}

    virtual CompleteResult Complete(bool wasCanceled, std::shared_ptr<void> status) = 0;
    virtual bool WaitForCompletion(int timeoutInMs) = 0;
    virtual bool IsCompleted() const = 0;
    virtual bool WasCanceled() const = 0;
    virtual std::shared_ptr<void> GetStatus() const = 0;
    virtual void Reset() = 0;
    TYPEIDHASHFUNC(IObserver)
};

IObserver は、IObservable に追加できるオブザーバーです。IObservable が完了すると、Observable に追加された各オブザーバーで Complete メソッドが呼び出されます

class BasicObserver : public IObserver{
private:
    bool isCompleted;
    bool wasCanceled;
    CompleteResult completeResult;
    std::shared_ptr<void> status;
    std::timed_mutex mutex;
public:
    BasicObserver(CompleteResult completeResult);
    ~BasicObserver();

    CompleteResult Complete(bool wasCanceled, std::shared_ptr<void> status);
    bool WaitForCompletion(int timeoutInMs);
    bool IsCompleted() const;
    bool WasCanceled() const;
    std::shared_ptr<void> GetStatus() const;
    void Reset();
    TYPEIDHASHFUNC(BasicObserver)
};

これは、オブザーバーの 1 つの実装です。ミューテックスを保持し、タイムアウトで WaitForCompletion を実装します。WaitForCompletion はブロックする必要があります。complete が呼び出されると、そのミューテックスのロックが解除されます。タイムアウトが実行されると、WaitForCompletion は false を返します

BasicObserver::BasicObserver(CompleteResult completeResult):
    isCompleted(false),
    wasCanceled(false),
    completeResult(completeResult)
{
    std::thread createThread([this]{
        this->mutex.lock();
    });
    createThread.join();
}

BasicObserver::~BasicObserver(){
}

CompleteResult BasicObserver::Complete(bool wasCanceled, std::shared_ptr<void> status){
    this->wasCanceled = wasCanceled;
    this->status = status;
    isCompleted = true;
    mutex.unlock();
    return completeResult;
}

bool BasicObserver::WaitForCompletion(int timeoutInMs){
    std::chrono::milliseconds time(timeoutInMs);
    if(mutex.try_lock_for(time)){
        mutex.unlock();
        return true;
    }else{
        return false;
    }
}

bool BasicObserver::IsCompleted() const{
    return isCompleted;
}

bool BasicObserver::WasCanceled() const{
    return wasCanceled;
}

std::shared_ptr<void> BasicObserver::GetStatus() const{
    return status;
}

void BasicObserver::Reset(){
    isCompleted = false;
    wasCanceled = false;
    status = 0;
    std::chrono::milliseconds time(250);
    mutex.try_lock_for(time); //if this fails it might be already resetted
}

//編集: 代わりにセマフォを使用して解決 (semaphore.h の sem_t)

4

2 に答える 2

0

ロック構造の再設計を検討します。メインスレッドがロックを保持していないのはなぜですか。イベント x が発生すると、ロックを解除します。一定期間ブロックする必要がある場合は、スレッドをスリープ状態にするだけです。同時に実行する必要がある場合は、ロックを取得したらすぐにロックを解放する必要がある場合は、すべての作業スレッドがロックを取得しようとしてミューテックスをブロックするようにします。

おそらく、イベント x をエミュレートするために 2 番目のミューテックスを使用します。

スレッド 1 からロックをセットアップしてから、何かを実行するスレッド 2 を開始し (この場合はハードウェアからの入力を待機)、スレッド 1 でミューテックスを待機します。スレッド 2 は、スイッチを押すとミューテックスのロックを解除します。ハードウェア。ある種のオブザーバーパターンを使用しています。だから私はオブザーバーを追加するところに何か観察可能なものを持っています(この場合、クラスAはオブザーバーです)。ある時点で、オブザーバブルは追加されたすべてのオブザーバーにタスクを完了したことを伝え、ミューテックスのロックを解除します。ここにはハードウェアがあるため、ハードウェアがロックするか、センサーが機能しない可能性があります。だから私はタイムアウトが必要です。– fredllll 3分前

編集- 多分これはうまくいくでしょうか?

スレッド 2 がそのロックで入力ブロックを取得した後、スレッド 1 でロックを保持します。タイムアウト時間後にスレッド 1 にロックを解放させ、スレッドが通過できるように少しスリープしてから、再度ロックを取得します。スレッド 2 がロック 1 を解放し、ミューテックス 1 を取得した後、2 番目のミューテックスでブロックを開始し、ハードウェア スイッチでミューテックス 2 のロックを解除し、スレッド 2 がミューテックス 2 をロックしてからミューテックス 2 のロックを解除します。ハードウェア スイッチでミューテックス 2 を再度取得します。

于 2014-02-28T00:28:38.130 に答える
0

condation_variable具体的には、wait_untilまたはwait_forを使用できます。

于 2014-02-28T00:20:37.150 に答える