Добавлю результаты тестов скорости (I7 HT — 4/8 x64 win7, MS2010):
| | Код теста |
| | SmartSpinMutex mtx;
SpinMutex sm;
CRITICAL_SECTION cs;
long cnt = 0;
DWORD WINAPI Entry(void *)
{
bool first = _InterlockedIncrement(&cnt) == 1;
while(1)
{
//mtx.Lock();
//sm.Lock();
EnterCriticalSection(&cs);
if (!first) Sleep(1);
_InterlockedIncrement(&cnt);
LeaveCriticalSection(&cs);
//mtx.Unlock();
//sm.Unlock();
if (!first) Sleep(10);
}
}
|
| | |
| | SmartSpinMutex |
| | class SmartSpinMutex
{
public:
SmartSpinMutex() : pEvent(&g_Event), m_lock(0) {}
void Lock()
{
for (__int64 index = pEvent->BeginWait();
::_InterlockedIncrement(&m_lock) > 1;
index = pEvent->BeginWait())
{
pEvent->PerformWait(index, INFINITE);
}
}
void Unlock()
{
if (::_InterlockedExchange(&m_lock, 0) != 1)
pEvent->Pulse();
}
private:
static PulsarEvent g_Event;
PulsarEvent * pEvent;
long m_lock;
};
DECLSPEC_SELECTANY PulsarEvent SmartSpinMutex::g_Event;
|
| | |
| | SpinMutex |
| | class SpinMutex
{
public:
SpinMutex() : m_lock(0) {}
void Lock()
{
while (_InterlockedCompareExchange(&m_lock, 1, 0))
SwitchToThread();
}
void Unlock()
{
_InterlockedExchange(&m_lock, 0);
}
private:
long m_lock;
};
|
| | |
1 поток
CRITICAL_SECTION: 2,158,300,174
SpinMutex: 2,671,681,914
SmartSpinMutex: 2,052,295,164
2 потока
CRITICAL_SECTION: 1,952,741,620
SpinMutex: 2,422,393,231
SmartSpinMutex: 1,857,165,297
20 потоков
CRITICAL_SECTION: 416,256
SpinMutex: 88,314
SmartSpinMutex: 1,069,619
*cnt после минуты
Резюмирую: пустые или малоконкурентные локи работают так-же, как у критической секции, с конкуренцией требующей ожиданий более эффективен, при этом не требует системных объектов(на указатель больше спинлока, и можно раздавать его хоть каждому объекту в программе)