递减原子计数器 - 但在<only>一定条件下
Decrement atomic counter - but <only> under a condition
我想在这行实现一些东西:
inline void DecrementPendingWorkItems()
{
if(this->pendingWorkItems != 0) //make sure we don't underflow and get a very high number
{
::InterlockedDecrement(&this->pendingWorkItems);
}
}
如何做到这一点,使两个操作作为一个块都是原子操作,而不使用锁?
您只需检查InterlockedDecrement()
的结果,如果它恰好为负(或者<=0,如果更可取),则通过调用InterlockedIncrement()
来撤消递减。在其他适当的代码中,这应该很好。
最简单的解决方案就是在整个部分使用互斥(以及用于对this->pendingWorkItems
的所有其它接入)。如果有的话原因是这是不可接受的,那么你可能需要比较交易所:
void decrementPendingWorkItems()
{
int count = std::atomic_load( &pendingWorkItems );
while ( count != 0
&& ! std::atomic_compare_exchange_weak(
&pendingWorkItems, &count, count - 1 ) ) {
}
}
(这假设pendingWorkItems
具有类型std::atomic_int
。)
有一种东西叫做"SpinLock"。这是一个非常轻量级的同步。
这就是想法:
//
// This lock should be used only when operation with protected resource
// is very short like several comparisons or assignments.
//
class SpinLock
{
public:
__forceinline SpinLock() { body = 0; }
__forceinline void Lock()
{
int spin = 15;
for(;;) {
if(!InterlockedExchange(&body, 1)) break;
if(--spin == 0) { Sleep(10); spin = 29; }
}
}
__forceinline void Unlock() { InterlockedExchange(&body, 0); }
protected:
long body;
};
样本中的实际数字并不重要。这把锁效率极高。
您可以在循环中使用InterlockedCompareExchange
:
inline void DecrementPendingWorkItems() {
LONG old_items = this->pendingWorkingItems;
LONG items;
while ((items = old_items) > 0) {
old_items = ::InterlockedCompareExchange(&this->pendingWorkItems,
items-1, items);
if (old_items == items) break;
}
}
InterlockedCompareExchange
函数的作用是:
if pendingWorkItems matches items, then
set the value to items-1 and return items
else return pendingWorkItems
这是以原子方式完成的,也称为比较和交换。
使用原子CAS。http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560(v=vs.85).aspx
你可以让它免费上锁,但不能免费等待。
正如Kirill所建议的,这类似于你的情况下的旋转锁。
我认为这正是你所需要的,但我建议在使用之前考虑所有的可能性,因为我根本没有测试过:
inline bool
InterlockedSetIfEqual(volatile LONG* dest, LONG exchange, LONG comperand)
{
return comperand == ::InterlockedCompareExchange(dest, exchange, comperand);
}
inline bool InterlockedDecrementNotZero(volatile LONG* ptr)
{
LONG comperand;
LONG exchange;
do {
comperand = *ptr;
exchange = comperand-1;
if (comperand <= 0) {
return false;
}
} while (!InterlockedSetIfEqual(ptr,exchange,comperand));
return true;
}
还有一个问题是,为什么你的待处理工作项应该低于零。你真的应该确保增量的数量与递减的数量相匹配,一切都会好起来的。如果违反了这个约束,我可能会添加一个断言或异常。
相关文章:
- EASTL矢量<向量<int>>连续的
- 这对"With a stackless coroutine, only the top-level routine may be suspended."意味着什么
- 如何修复输出日志中的"EnableInput can only be specified on a Pawn for its Controller"错误
- 如何理解"abstract-declarator containing an ellipsis shall only be used in a parameter-declaration"
- 开发QR扫描仪以扫描我生成的"only" QR码?
- Protobuf 生成的C++类无法针对 iOS 进行编译,并显示错误"Only virtual member functions can be marked 'final'"
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- Windows 10 环境中的"This version of XAudio2 is available only in Windows 8"错误
- C 字符串比较“祝您好运”&gt;“再见”
- CUDA 内核"Only a single pack parameter is allowed"解决方法?
- 为什么仅 -fno-signed-0 就可以实现优化,而似乎也需要 -ffinite-math-only (gcc)
- 在 c++11 模式下使用 QtConcurrent::run with move only 参数
- 为什么这句话"The expression can be used only as the left-hand operand of a member function call"在 [expr.re
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- 平息海湾合作委员会的"only available with -std=c++XX or -std=gnu++XX"警告
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 为什么 std::optional 不允许"move construct and copy assign only"类型的移动分配?
- C 操作员&gt;&gt;与突变器过载
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 是否需要使用 - &gt;运算符在C 中调用成员函数时