2017-05-03 10 views
5

私は、並行プログラミングを始めています。おそらく私の問題は非常に一般的ですが、私はそれの良い名前を見つけることができないので、私はそれをGoogleすることはできません。関数のインスタンスが1つしか実行されていないことを確認しますか?

私はMVVMパターンを適用しようとするC++ UWPアプリケーションを持っていますが、パターンやUWPも関係ないと思います。私は具体的な実装を提供しますが、それはこの議論には関係ありませんが、もちろん

struct IService 
{ 
    virtual task<int> Operation() = 0; 
}; 

まず、私が操作を公開するサービス・インターフェースを持っています。この操作は長時間実行される可能性があります。つまり、HTTP要求を行います。

それから私は(再び、無関係な詳細は省略)サービスを使用するクラスを持っている:私はコルーチンを使用

class ViewModel 
{ 
    unique_ptr<IService> service; 
public: 
    task<void> Refresh(); 
}; 

task<void> ViewModel::Refresh() 
{ 
    auto result = co_await service->Operation(); 
    // use result to update UI 
} 

リフレッシュ機能は、タイマーで毎分起動され、またはユーザーの要求に応じて私が欲しいのは、新しい操作が開始または要求されたときにリフレッシュ操作がすでに進行中で、次に2番目の操作を中止し、最初の操作が完了するまで待つ(またはタイムアウトする)ことです。言い換えれば、私はすべてのコールをリフレッシュにキューイングしたくありません。コールがすでに進行中の場合は、次のタイマーティックまでコールをスキップすることをお勧めします。 (おそらく非常にナイーブ)

私の試みでした:それは違いはありませんように私は、上記のコードの行をコメントアウト:

mutex refresh; 
task<void> ViewModel::Refresh() 
{ 
    unique_lock<mutex> lock(refresh, try_to_lock); 
    if (!lock) 
    { 
     // lock.release(); commented out as harmless but useless => irrelevant 
     co_return; 
    } 
    auto result = co_await service->Operation(); 
    // use result to update UI 
} 

編集オリジナルのポストの後。問題はまだ同じです。

もちろん、アサーションが失敗します:unlock of unowned mutex。私は問題がmutexによってunique_lockデストラクタによってunlockであると推測します。これはコルーチンの継続と別のスレッド(最初はロックされていたものを除く)で起こります。

のVisual C++ 2017

+0

@WhozCraig、私は試していませんが、私はどのような提案にも開放されています - あなたはコード例を挙げられますか? –

+0

本当に素朴な解決策: 'std :: atomic running'。 – MSalters

+3

あなたはロックされていないことが分かっているロックを解放しようとしているという事実については問題があると思いませんか? – UKMonkey

答えて

1

使用std::atomic_bool使用:RAIIクラスでisRunning.storeをラップし、寿命atomic_boolがスコープされている場合場合std::shared_ptr<std::atomic_bool>を使用します。

std::atomic_bool isRunning = false; 
if (isRunning.exchange(true, std::memory_order_acq_rel) == false){ 
    try{ 
    auto result = co_await Refresh(); 
    isRunning.store(false, std::memory_order_release); 
    //use result 
    } 
    catch(...){ 
    isRunning.store(false, std::memory_order_release); 
    throw; 
    } 
} 

二つの可能な改善を。

+0

解決策は機能し、他のものはありません(少なくともここにはありません)ので、私はそれを受け入れます。しかし私は2つのコメントがあります。 1)標準ライブラリが標準的なソリューションを提供していないという事実に私は失望しています。これは答えの価値を減らすものではありません。 2) 'std :: atomic_bool'を' std :: atomic_flag'に置き換えることはできませんでしたか?'std:atomic_bool'はより多くの機能(より詳細な制御)を提供しますが、どのような付加価値を提供しますか?それが何らかの最適化であることを理解しましたが、それはどれくらい重要ですか? –

+0

1)this *は標準的な解決法です2) 'std :: atomic_flag'はここで使用できますが、個人的には' std :: atomic_flag'を 'std :: call_once'だけで使うと思います。 –

関連する問題