Kurs Qt – Część 4 – Wątki

Matthew @ 2009-07-26 — Kategorie: Kurs Qt, Programowanie, Qt, Techblog

Kolejna cześć kursu Qt. Tym razem będzie o wątkach. Niestety, praca i brak niebezpieczeństwa zawalenia egzaminów strasznie rozleniwiają, więc dopiero teraz udało mi się zebrać i coś napisać (nie lubię wakacji, masa czasu a nic nie udaje się zrobić ;)). Stworzymy proste wątki, będzie to tradycyjny przykład producenta i konsumenta. Na początku z wyścigami, później postaramy się przed nimi zabezpieczyć. A więc do dzieła:

Aby stworzyć wątek należy utworzyć klasę, która będzie dziedziczyła po QThread oraz implementowała metodę run(). Najprościej wygląda to tak:

Taki wątek (po utworzeniu obiektu klasy) uruchamiamy metodą start():

Z kolei metoda wait() blokuje wątek do momentu w którym metoda run() nie zwróci wyniku lub czeka aż upłynie odpowiedni czas (podawany z milisekundach jako argument). A teraz przykład praktyczny:

Kod producenta i konsumenta są bardzo proste. Mają magazyn, do którego dokładają lub pobierają dane. Oraz licznik, żeby wiedzieli która, ostatnia, półka jest zajęta. Wprowadziliśmy również pewne opóźnienia w pętlach wątków, aby całość wykonywała się trochę wolnej. Dodatkowe opóźnienie między zapisem/odczytem, a zmianą licznika, pozwala nam także zaobserwować możliwe wyścigi. Trochę to na siłę, ale w przeciwnym wypadku, dla tak prostego programu, bardzo trudno by było o taką sytuację (chociaż w przypadku bardziej złożonych aplikacji zdarza się to bardzo często). Teraz, aby pozbyć się wyścigów dodajemy jeden mutex. Blokujemy go również przed wykorzystaniem wrażliwych na wyścigi zmiennych:

Kod metodu run()  konsumenta wygląda analogicznie. Dzięki temu prostemu zabiegowi pozbyliśmy się wyścigów. Możliwe jest również odmienne podejście do tematu z wykorzystaniem QWaitCondition . Jest to klasa, która pozwala synchronizować wiele wątków. Dzięki temu, jeden wątek może powiedzieć innym, że zaszło pewne zdarzenie, przez co pobudzić je do działania. A ponieważ nie warto od nowa wymyślać koła, posłużymy się przykładem danym nam przez Qt Software i tylko omówię co ciekawsze fragmenty:

Obiekt bufferNotFull  informuje producenta o tym, że bufor przestał być pełen i znowu może zacząć się zapis. Z kolei bufferNotEmpty  pilnuje konsumentów, żeby nie zaczęli czytać z pustego bufora. Jak widać, nie musimy również blokować mutexem samego zapisu, gdyż wystarczy, że będziemy tylko sprawdzać czy pojawiły się nowe dane do odczytu (producent zwiększa licznik gdy coś dołoży, konsument zmniejsza gdy zabierze).

To tyle, jeżeli chodzi o proste przedstawienie wątków. Gdyby ktoś zamiast mutexów i waitCondition chciał wykorzystać semafor, to tutaj znajduje się analogiczny przykład. Mam nadzieję, że na następną cześć nie będziecie musieli czekać aż tak długo. :)

Komentarze:

Skąd można pobrać ten spakowany projekt QT ?

https://github.com/matthewpl/ tutaj tego niema ;/

Wtedy nie było jeszcze gotowych projektów i nie sądzę (nie mam teraz jak tego sprawdzić) żebym miał go w swoich zasobach, musisz ręcznie przepisać. ;)

Cześć :)
Jestem początkujący i nie ogarniam czasami kodu :(
Dobrze by było gdybyś w komentarzach w kodzie pisał co się wykonuje tak jak pisałes tu :
const int rozmiar = 8192; // rozmiar bufora
int magazyn[rozmiar]; // bufor
int zajetosc = 0; // zajetosc bufora

Jaśniej by było przynajmniej dla mnie

Dodaj komentarz:

 

Subscribe without commenting