Skip to main content

Wielowątkowość – Sygnały

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.

markac

Full-stack Web Developer

3 thoughts to “Wielowątkowość – Sygnały”

  1. 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.

  2. 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.

    1. 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.

Komentarze są zamknięte.