2017-10-23 5 views
3

私は、多くのスレッドが0にアクセスできる(同時に共有リソースなし)という機能を持っています(関数Aと呼ぶことができます)。いつでも、ユーザーはプロセスを停止するために使用できます。停止機能は、正常なシャットダウンを実行できるように、機能Aにアクセスするスレッドが存在することを確認する必要があります。そうするネイティブな手順はありますか?メソッドと停止機能の間の正しい同期方法

私がしようとしていたのは、関数Aが呼び出されるたびに(関数Aが存在するときには整数に対応するInterlockedDecrement)、整数をInterlockedIncrementにすることです。 InterlockedDecrementが発生すると整数の値をチェックし、ゼロに設定されている場合はイベントがシグナルに設定されます。値がゼロでない場合、イベントは非シグナリングに設定されます。

これは私の心では理にかなっていますが、これに対応するネイティブな構造/機能があるかどうかは不思議です。

「停止」機能が枯渇しているという意味では、まだ意味があります(この意味で、前記の整数は決してゼロに設定されないかもしれません)。 sidenote:停止イベントが発生したとき、InterlockedIncrementプロセスを停止して、その飢餓を減らす。

答えて

4

Run-Down Protectionと呼ばれています。残念ながら、それはカーネルモードでしかサポートされていませんでしたが、あなた自身もユーザーモードでハードに実装していません。

最も簡単な実装は次です:

HANDLE ghStopEvent; 
LONG gLockCount = 1; 
BOOLEAN bStop = FALSE; 

void unlock() 
{ 
    if (!InterlockedDecrement(&gLockCount)) SetEvent(ghStopEvent); 
} 

BOOL lock() 
{ 
    LONG Value = gLockCount, NewValue; 

    for (; !bStop && Value; Value = NewValue) 
    { 
     NewValue = InterlockedCompareExchange(&gLockCount, Value + 1, Value); 

     if (NewValue == Value) return TRUE; 
    } 

    return FALSE; 
} 

void funcA(); 

void UseA() 
{ 
    if (lock()) 
    { 
     funcA(); 
     unlock(); 
    } 
} 

、あなたはランダウンを開始したい - 一度あなたがlock関数は1にしかならばインクリメントgLockCountを連動さ見ることができますどのように

bStop = TRUE; unlock();

を呼び出しますそれは0ではありません。

カーネルモードでは、代わりに

EX_RUNDOWN_REF gRunRef; 

void UseA() 
{ 
    if (ExAcquireRundownProtection(&gRunRef)) 
    { 
     funcA(); 
     ExReleaseRundownProtection(&gRunRef) 
    } 
} 

と場所にunlock最終 - ランダウン保護のいくつかのより複雑かつスケーラブルな実装ExWaitForRundownProtectionRelease


#define RUNDOWN_INIT_VALUE 0x80000000 
#define RUNDOWN_COMPLETE_VALUE 0 

class __declspec(novtable) RUNDOWN_REF 
{ 
    LONG _LockCount; 

protected: 

    virtual void RundownCompleted() = 0; 

public: 

    BOOL IsRundownBegin() 
    { 
     return 0 <= _LockCount; 
    } 

    void Reinit() 
    { 
     if (InterlockedCompareExchange(&_LockCount, RUNDOWN_INIT_VALUE, RUNDOWN_COMPLETE_VALUE) != RUNDOWN_COMPLETE_VALUE) 
     { 
      __debugbreak(); 
     } 
    } 

    RUNDOWN_REF() 
    { 
     _LockCount = RUNDOWN_INIT_VALUE; 
    } 

    BOOL AcquireRundownProtection() 
    { 
     LONG Value = _LockCount, NewValue; 

     for (; Value < 0; Value = NewValue) 
     { 
      NewValue = InterlockedCompareExchange(&_LockCount, Value + 1, Value); 

      if (NewValue == Value) return TRUE; 
     } 

     return FALSE; 
    } 

    void ReleaseRundownProtection() 
    { 
     if (RUNDOWN_COMPLETE_VALUE == InterlockedDecrement(&_LockCount)) 
     { 
      RundownCompleted(); 
     } 
    } 

    void BeginRundown() 
    { 
     if (AcquireRundownProtection()) 
     { 
      _interlockedbittestandreset(&_LockCount, 31); 
      ReleaseRundownProtection(); 
     } 
    } 
}; 

など、それを使用します。

class MY_RUNDOWN_REF : public RUNDOWN_REF 
{ 
    HANDLE _hEvent; 

    virtual void RundownCompleted() 
    { 
     SetEvent(_hEvent); 
    } 
    // ... 
} gRunRef; 


void UseA() 
{ 
    if (gRunRef.AcquireRundownProtection()) 
    { 
     funcA(); 
     gRunRef.ReleaseRundownProtection(); 
    } 
} 

としたときに停止したい:

gRunRef.BeginRundown();// can be safe called multiple times 
// wait on gRunRef._hEvent here 

興味深いカーネルに1(より古い - XPからの保護をランダウンWin2000の、からの)他に存在することをAPI Remove Locks。それはほとんど同じです。内部実装と使用法だけが異なります。

IO_REMOVE_LOCK gLock; 

void UseA() 
{ 
    if (0 <= IoAcquireRemoveLock(&gLock, 0)) 
    { 
     funcA(); 
     IoReleaseRemoveLock(&gLock, 0); 
    } 
} 

を、私たちは停止したいとき - 近くのロックの実装、第二に近い荒廃保護の実装を削除する実装によって

IoAcquireRemoveLock(&gLock, 0); 
IoReleaseRemoveLockAndWait(&gLock, 0); 

私の最初のコードスピネルを呼び出す:削除ロックコードと一緒に次のようになります。両方とも同じ意味です

+0

[インライン関数](https://docs.microsoft.com/en-us/cpp/cpp/inline-functions-cpp):*「 '__forceinline'キーワードはコストをオーバーライドします/利益分析を行い、代わりにプログラマーの判断に頼っています。[...] '' __forceinline'の無差別な使用は、限界性能の向上だけでなく、場合によってはパフォーマンスの低下さえも引き起こしますより大きい実行可能ファイルなど)」* – IInspectable

+0

@IInspectable - ok、私はここでプログラマーの判断を選択します。しかし、とにかくここでインラインで使用するかどうかは、私の実装のロジックを変更しないでください。 – RbMm

+0

プログラマの判断が間違っています。メンバ関数はすでに暗黙的にインライン化されています。これは無差別な使い方であり、視覚的な混乱を招き、実行時のパフォーマンスは '__forceinline'のないコードよりも良いか悪いかのどちらかになります。 – IInspectable

関連する問題