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);
私の最初のコードスピネルを呼び出す:削除ロックコードと一緒に次のようになります。両方とも同じ意味です
[インライン関数](https://docs.microsoft.com/en-us/cpp/cpp/inline-functions-cpp):*「 '__forceinline'キーワードはコストをオーバーライドします/利益分析を行い、代わりにプログラマーの判断に頼っています。[...] '' __forceinline'の無差別な使用は、限界性能の向上だけでなく、場合によってはパフォーマンスの低下さえも引き起こしますより大きい実行可能ファイルなど)」* – IInspectable
@IInspectable - ok、私はここでプログラマーの判断を選択します。しかし、とにかくここでインラインで使用するかどうかは、私の実装のロジックを変更しないでください。 – RbMm
プログラマの判断が間違っています。メンバ関数はすでに暗黙的にインライン化されています。これは無差別な使い方であり、視覚的な混乱を招き、実行時のパフォーマンスは '__forceinline'のないコードよりも良いか悪いかのどちらかになります。 – IInspectable