我想要了解这方面的一些东西:
inline void DecrementPendingWorkItems() { if(this->pendingWorkItems != 0) //make sure we don't underflow and get a very high number { ::InterlockedDecrement(&this->pendingWorkItems); } }
我怎么能做到这一点,使两个操作是primefaces的块,而不使用锁?
您可以只检查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
你可以让它自由锁定,但不能等待自由。
正如基里尔所说,这与你的情况下的自旋锁相似。
我认为这是你所需要的,但我建议在继续使用之前考虑所有的可能性,因为我还没有测试过它:
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; }
还有一个问题,为什么你的工作项目应该低于零。 你应该确保增量的数量与减少的数量相匹配,并且都可以。 如果违反了这个约束,我可能会添加一个断言或异常。