我想在这方面实现一些目标:
inline void DecrementPendingWorkItems()
{
if(this->pendingWorkItems != 0) //make sure we don't underflow and get a very high number
{
::InterlockedDecrement(&this->pendingWorkItems);
}
}
我怎样才能这样做,以便两个操作都是块状的,而不使用锁?
答案 0 :(得分:2)
您可以检查InterlockedDecrement()
的结果,如果它恰好为负数(或者如果更合适,则为< = 0)通过调用InterlockedIncrement()
来撤消减量。在其他正确的代码中应该没问题。
答案 1 :(得分:2)
最简单的解决方案是在整个部分使用互斥锁
(以及对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
。)
答案 2 :(得分:0)
有一种叫做“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;
};
样本中的实际数字并不重要。这种锁非常有效。
答案 3 :(得分:0)
您可以在循环中使用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
这是以原子方式完成的,也称为比较和交换。
答案 4 :(得分:0)
使用原子CAS。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560(v=vs.85).aspx
你可以免费锁定,但不能等待免费。
正如基里尔所说,这与你的情况下的自旋锁类似。
我认为这可以满足您的需求,但我建议您在继续使用之前考虑所有可能性,因为我根本没有测试过它:
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;
}
还有一个问题是,为什么待处理的工作项目应该低于零。你应该确保增量的数量与减量的数量相匹配,一切都会好的。如果违反了这个约束,我可能会添加一个断言或异常。