W poprzednim artykule opisałem podstawowe zagadnienia z dziedziny wielowątkowości, a także wyjaśniłem zasadę działania wątków typu Worker.
Zapoznanie się z poprzednim artykułem jest fakultatywne ;D:
http://blog.kacki.pl/dev/worker-threads/.
Wstęp
Cała platforma bada opiera się o wielowątkowość typu Event-driven threads (opartej na zdarzeniach), gdzie aby zakończyć wątek, trzeba wysłać sygnał końca metodą Stop().
Dodatkowo wątki tego typu umożliwiają wysyłanie i odbieranie komunikatów do/z innych wątków (asynchroniczne operacje).
Tworzenie
Aby stworzyć wątek typu Event-Driven wystarczy wyprowadzić nową klasę dziedziczącą po klasie Thread. Dla przypomnienia hierarchia klas:
Klasa Thread posiada kilka metod wirtualnych, których implementacja jest opcjonalna.
Oto niektóre z nich:
virtual bool OnStart(void); virtual void OnStop(void); virtual Osp::Base::Object* Run(void);
OnStart() – Zdarzenie uruchomienia wątku.
OnStop() – Zdarzenie zatrzymania wątku.
Klasa Thread dostarcza domyślną implementację metody Run() z interfejsu IRunnable – nie powinniśmy jej przesłaniać – jeśli to zrobimy, wątek będzie się zachowywał jak typu Worker i po wyjściu z tej metody wątek zostanie automatycznie zakończony.
Implementacja
/* * MyTask.h * * Created on: 28-10-2011 * Author: markac */ #ifndef MYTASK_H_ #define MYTASK_H_ #include <FBase.h> using namespace Osp::Base; using namespace Osp::Base::Runtime; class MyTask : public Thread { public: MyTask(); virtual ~MyTask(); virtual bool OnStart(void); virtual void OnStop(void); }; #endif /* MYTASK_H_ */
/* * MyTask.cpp * * Created on: 28-10-2011 * Author: markac */ #include "MyTask.h" MyTask::MyTask() { // TODO Auto-generated constructor stub } MyTask::~MyTask() { // TODO Auto-generated destructor stub } bool MyTask::OnStart() { // inicjalizacja zadania i uruchomienie return true; // false - natychmiastowe zakończenie wątku } void MyTask::OnStop() { // zwolnij zajęte zasoby }
Uruchamianie
MyTask* pThread = new MyTask(); pThread->Construct(THREAD_TYPE_EVENT_DRIVEN); // THREAD_TYPE_WORKER dla typu Worker pThread->Start();
Zatrzymywanie
Aby zakończyć wątek, wywołujemy metodę Stop().
// zatrzymaj zadanie pThread->Stop(); // tylko dla typu THREAD_TYPE_EVENT_DRIVEN // czekaj na zakończenie zadania pThread->Join(); // usuń wątek delete pThread; pThread = null;
Różnice między wątkami typu Worker i Event-Driven
Dobrze ilustruje to poniższy obrazek, który zdecydowałem się przytoczyć jeszcze raz.
Worker threads – po wykonaniu zadania w ciele metody Run(), wątek zostaje automatycznie zakończony.
Event-driven threads – wątek z obsługą zdarzeń/powiadomień, działający do chwili uzyskania sygnału zatrzymania metodą Stop().
Na tym różnice się nie kończą. Wątki typu Event-Driven posiadają obsługę zdarzeń/sygnałów odbieranych z innych wątków.
O komunikacji między wątkami będzie traktował jeden z kolejnych artykułów.
Podsumowanie
Aby stworzyć wątek typu Worker:
- Wyprowadzamy nową klasę implementującą interfejs IRunnable lub dziedziczącą po klasie Thread.
- Przesłaniamy metodę Run() i w ciele metody umieszczamy nasze zadanie.
- Zakończenie wątku nastąpi automatycznie po wyjściu z metody Run().
Aby stworzyć wątek typu Event-Driven:
- Wyprowadzamy nowa klasę dziedziczącą po klasie Thread.
- Nie przesłaniamy domyślnej metody Run(), a zadanie umieszczamy w metodzie OnStart().
- Kończymy wątek metodą Stop().
Dyskusja dostępna także na forum:
http://forum.badadev.pl/viewtopic.php?id=52