Koszt CRITICAL_SECTION
Pisanie aplikacji, które są i wydajne i przyjazne użytkownikowi wymaga użycia wielowątkowości. Wiadomo, jeśli będziemy coś liczyć na wątku odpowiedzialnym za rysowanie interfejsu to tego rysowania w tym czasie nie będzie i otrzymamy aplikację, która nie odpowiada. Tak jest np. w przypadku paska menu Start. Wystarczy kliknąć na na “Moje bieżące dokumenty” czy spróbować wyświetlić menu “Połącz z”. Musimy wtedy swoje odczekać. Gdy do tego jeszcze któryś z plików (z bieżących dokumentów) jest poza naszym komputerem to gwarantowane czekanie kilkadziesiąt sekund. W tym czasie pasek startu jest zawieszony w obowiązkach.
Tak czy inaczej podczas jednej z takich sytuacji zacząłem się zastanawiać jaki to wielki koszt czasowy jest związany z blokowaniem za pomocą CRITICAL_SECTION. Oto malutki program, który mi posłużył do testów:
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
int testValue = 0;
LARGE_INTEGER lintStart, lintEnd;
LARGE_INTEGER lintFreq;
QueryPerformanceFrequency(&lintFreq);
QueryPerformanceCounter(&lintStart);
int i;
for(i=0; i<1000000; i++)
{
EnterCriticalSection(&cs);
testValue = i;
LeaveCriticalSection(&cs);
}
QueryPerformanceCounter(&lintEnd);
std::cout << boost::format("CPU Freq: %1% Hz")
% lintFreq.QuadPart << std::endl;
std::cout << boost::format("Cycles per enter/leave: %1%")
% (double(lintEnd.QuadPart-lintStart.QuadPart)
/ double(i)) << std::endl;
No i cóż się okazało? Na moim Core 2 Duo koszt zablokowania sekcji krytycznej i jej zwolnienia to całe 90-100 cykli zegara CPU. Jeśli metodyka pomiaru była prawidłowa to jest to bardzo mały narzut. Wydaje się zatem, że zysk dla użytkownika programu, który nie musi czekać aż łaskawie program skończy jakąś operację, jest o wiele większy niż koszt. Czy zatem programiści od Windows Explorera nie mogliby tego zastosować, aby żyło się nieco łatwiej z ich systemem?