Wstęp
Aplikacje wielowątkowe wymagają mechanizmu umożliwiającego komunikowanie się wątków między sobą.
Komunikacja taka musi odbywać się w sposób bezpieczny, aby równolegle wywołanie tej samej metody (części kodu) przez różne wątki nie powodowało żadnych problemów.
Kolizja wątków mogłaby nastąpić w momencie, kiedy dwa watki próbują odwołać się do tego samego zasobu.
Fragmenty kodu, które są wywoływane przez wiele wątków jednocześnie i są bezpieczne, tzn. gwarantują, że tylko jeden wątek jednocześnie może operować na danym fragmencie kodu nazywają się thread-safe.
Przykładem metody thread-safe jest Osp::Base::Utility::Math::Sin(x).
Wg. dokumentacji, w większości metody statyczne klas zawartych w platformie bada są oznaczone jako thread-safe.
Przeciwieństwem metod thread-safe są metody oznaczone jako not thread-safe.
Sygnały
System bada nie wspiera mechanizmu Signals 🙂 Dokumentacja zaleca w to miejsce zastosowanie mechanizmu zdarzeń.
Zdarzenia
Klasa Thread posiada dwie metody, z których jedna odpowiada za wysyłanie powiadomień, druga pozwala na ich odbiór:
result Osp::Base::Runtime::Thread::SendUserEvent(RequestId requestId, const Osp::Base::Collection::IList* pArgs); virtual void Osp::Base::Runtime::Thread::OnUserEventReceivedN(RequestId requestId, Osp::Base::Collection::IList* pArgs);
Metody posiadają identyczne argumenty, z których:
- requestId to zwykła liczba typu int identyfikująca rodzaj sygnału,
- pArgs to wskaźnik do kolekcji dodatkowych argumentów.
Sufiks N w nazwie funkcji OnUserEventReceivedN() oznacza, że musimy sami zadbać o zwolnienie pamięci zajmowanej przez zasoby.
W tym przypadku chodzi o zwolnienie pamięci zajmowanej przez kolekcję z dodatkowymi parametrami, do której wskaźnik uzyskujemy w drugim argumencie pArgs.
Aby watek mógł odbierać zdarzenia, musimy przesłonić metodę OnUserEventReceivedN().
Wykorzystanie
Zastosowań jest tyle ilu programistów. Dla przykładu, wszystkie formularze w naszej aplikacji chciałyby komunikować się z klasą główną aplikacji i zlecać jej aktywację innego formularza np. po przejściu na inną zakładkę lub naciśnięciu przycisku.
Innym przykładem może być odtwarzacz dźwięku, do którego chcielibyśmy wysyłać sygnały (komendy) o przejściu w stan:
- Play(),
- Pause(),
- Stop().
Jeszcze innym sygnałem może być np. sygnał zakończenia wątku lub jego uśpienia.
Odbieranie zdarzeń
void AlleClient::OnUserEventReceivedN(RequestId requestId, Osp::Base::Collection::IList* pArgs) { Frame *pFrame = GetAppFrame()->GetFrame(); switch (requestId) { case USER_EVENT_FORM_CATEGORIES: { pFrame->SetCurrentForm(*__pCategoriesForm); __pCategoriesForm->Draw(); __pCategoriesForm->Show(); break; } case USER_EVENT_FORM_AUCTIONS: { pFrame->SetCurrentForm(*__pAuctionsForm); __pAuctionsForm->Draw(); __pAuctionsForm->Show(); break; } } }
Wysyłanie zdarzenia
Wysłanie zdarzenia z formularza informujące o chęci zmiany aktualnego formularza na inny:
Osp::App::Application::GetInstance()->SendUserEvent(AlleClient::USER_EVENT_FORM_CATEGORIES, null);
Wyjaśnienie
Nie jest to kompletny kod aplikacji, ale zawarte jest wszystko co wymagane do zrozumienia zagadnienia.
USER_EVENT_FORM_* to zwykłe stałe statyczne typu RequestId zdefiniowane w mojej aplikacji.
Poniżej poglądowy rysunek działania kodu.
Nie udało mi się napisać odpowiednika kodu, który prezentowałby dokładne działanie sygnałów, jakie występują w C#.
Zabrakło mi tutaj funkcji oczekującej na sygnał, jak: WaitOne(), WaitAll() i WaitAny(), które wznawiałaby działanie wątku dopiero po otrzymaniu sygnału.
Chętnie widziałbym tutaj dyskusję w tym temacie, jak wy implementujecie sygnały w bada.
Witam,
takie funkcje oczekujące posiada monitor. Chociaż nie do końca. Według dokumentacji funkcją oczekująca jest Osp::Base::Runtime::Monitor::Wait(void) (innych nie ma, więc nie możemy czekać na kilka sygnałów). Natomiast możemy powiadamiać jeden oczekujący wątek Osp::Base::Runtime::Monitor::Notify(void) lub wszystkie oczekujące wątki Osp::Base::Runtime::Monitor::NotifyAll(void).
Pozdrawiam.
Monitory raczej mogłyby się nadać, ale jeśli szukasz w SDK coś o sygnałach to odsyłają właśnie do opisywanych zdarzeń.
Kolejne artykuły będą właśnie o monitorach, semaforach i muteksach.