Witam. Piszę w C++ pewną bibliotekę. Głównym jej założeniem jest to, aby była ona niezależna od innych bibliotek (oprócz biblioteki standardowej C++). Ostatnio zabrałem się za pisanie klasy obsługującej wątki - Thread. Ten fragment jest OK, ale problem pojawił się przy klasach odpowiedzialnych za synchronizację wątków. Napisałem klasę CriticalSection oraz Mutex (za semafory zabiorę się dopiero po ukończeniu muteksów).
Tu jest miejsce na pierwsze pytanie: czy w danym procesie może istnieć kilka/kilkanaście sekcji krytycznych (nie chodzi mi o sytuację synchronizacji dwóch wątków za pomocą dwóch sekcji, gdyż wiadomo, że to nie ma sensu :-) ) oraz czy to nie jest w jakiś sposób "niebezpieczne" (albo może lepiej bez cudzysłowie... ;] ).
Drugi problem dotyczy muteksów. Porównałem to co oferuje Windows z tym co daje biblioteka Qt4. I doszedłem do wniosku, że klasa QMutex działa o wiele sprawniej niż funkcje Windowsa. Czy ktoś mógłby mi odpowiedzieć na pytanie: dlaczego? Qt jest biblioteką wielopratformową więc może ona wcale nie korzysta z funkcji CreateMutex(), CloseHandle() itd. ? A jeśli tak rzeczywiście miałoby być, to jaka jest alternatywa?
Jeśli chcecie sprawdzić obie wersje (funkcje Windowsa i klasa QMutex) u siebie, to zamieszczę tutaj mój kod, żeby się nie przemęczać ;]. Program uruchamia dwa wątki i w jednym z nich inkrementuje a w drugim dekrementuje globalną zmienną.
#include <iostream>
#include <windows.h>
#include <QMutex>
using namespace std;
int a = 0;
DWORD id1, id2;
HANDLE thread1, thread2;
HANDLE mutex;
QMutex qmutex;
//#define lock_by_qmutex // <-- usuń komentarz aby użyć klasy QMutex
// niekiedy makrodefinicje ułatwiają życie :D
#ifdef lock_by_qmutex
#define lock qmutex.lock();
#define unlock qmutex.unlock();
#else
#define lock WaitForSingleObject(mutex, INFINITE);
#define unlock ReleaseMutex(mutex);
#endif
DWORD WINAPI threadMain(void*)
{
for(unsigned u = 0; u < 1000000; ++u)
{
lock; // blokada zasobów
if(GetCurrentThreadId() == id1) // żeby nie pisać osobno ciał obu funkcji
++a;
else --a;
unlock; // odblokowanie zasobów
}
return 0;
}
int main(int argc, char* argv[])
{
// "inicjalizacja czasomierza"
DWORD time1 = GetCurrentTime();
// utworzenie mutex'u i dwóch wątków
mutex = CreateMutex(0, false, 0);
thread1 = CreateThread(0, 0, threadMain, 0, 0, &id1);
thread2 = CreateThread(0, 0, threadMain, 0, 0, &id2);
cout << "Czekam\n";
// czekanie na zakończenie pracy obu wątków
WaitForSingleObject(thread1, INFINITE);
WaitForSingleObject(thread2, INFINITE);
// wynik zgodnie z oczekiwaniami jest zerem
cout << "a = " << a << endl;
// różnicę w czasie wykonywania programu w obu wariantach
// będzie widać gołym okiem, ale tak dla porządku jeszcze
// krótkie info nt. czasu trwania.
DWORD time2 = GetCurrentTime();
double time = (time2-time1)/1000.0;
cout << "Wykonano po " << time << endl;
cout << "Wcisnij dowolny klawisz.";
cin.get();
return 0;
}