Be Book Application Kit Application Kit Indeks

BLooper

Pochodzi od: public BHandler
Zadeklarowany w:  be/app/Looper.h
Biblioteka: libbe.so
Podsumowanie:  więcej...

Obiekt BLooper tworzy "pętlę komunikatu", otrzymującą komunikaty, które są wysłane lub przesłane do BLooper'a. Pętla komunikatu działa w oddzielnym wątku, który jest utworzony (i opowiedział, że działa) gdy BLooper odbiera wywołanie Run(). Jeśli tworzysz swój własny BLooper, możesz wywołać Run() z wnętrza konstruktora.

Aby pętla się zatrzymała, mówisz je to przez wysłanie BLooper'owi komunikatu B_QUIT_REQUESTED, który wywołuje funkcję Quit() obiektu. Możesz również wywołać Quit() bezpośrednio, ale musisz najpierw zablokować obiekt poprzez Lock() (blokowanie BLooper'a jest wyjaśnione później). Quit() niszczy BLooper za Ciebie.

The BApplication class, the most important BLooper subclass, bends the above description in a couple of ways:

Posłańcy i handler'y (obsługiwacze)

Możesz dostarczyć komunikaty do wątku BLooper przez...

Gdy komunikaty nadchodzą są one dodawane do obiektu BMessageQueue BLooper'a. BLooper pobiera komunikaty z kolejki w kolejnośi takiej jak one nadchodziły i wywołuje DispatchMessage() dla każdego z nich. DispatchMessage() blokuje BLooper a wtedy podaje komunikat do obiektu BHandler'a przez wywołanie funkcji MessageReceived() handler'a. Ale do którego BHandler'a BLooper podaje komunikat? Tutaj jest ścieżka:

Po zakończeniu działania handler'a (gdy jego funkcja MessageReceived() zwróci wartość), BMessage jest automatycznie niszczony a BLooper jest odblokowywany.

Blokowanie

Dostęp do wielu funkcji BLooper'a (i niektóch funkcji BHandler'a) jest chroniony przez zamek. Do wywołnia funkcji chronionych przez zamek (lub grupy funkcji), musisz najpierw wywołać Lock(), a gdy już wykonasz działania wtedy wywołasz Unlock(). Zasięg zamka jest ograniczony do wywoływanego wątku: wywołania Lock()/Unlock() mogą być zagnieżdżone wewnątrz wątku. To znaczy, że każde Lock() musi być zrównoważne przez Unlock().

Konstruktor BLooper'a automatycznie blokuje obiekt. Jest on odblokowywany gdy jest wywoływana funkcja Run(). To znaczy, że funkcja Run() - i inne chronione zamkiem funkcje, które wywołujesz przed wywołaniem Run() - muszą być wywołane z wątku, który utworzył BLooper.

Alokacja

Ponieważ są one usuwane poprzez delete gdy powiedzą o zakończeniu, BLooper'y nie mogą być lokowane na stosie; musisz ich skonstruować z użyciem new.


Funkcje Przechwytujące


Konstruktor i Destruktor


BLooper()

BLooper(const char *name = NULL,
      int32 priority = B_NORMAL_PRIORITY,
      int32 portCapacity = B_LOOPER_PORT_DEFAULT_CAPACITY)
BLooper(BMessage *archive)

Przypisuje obiektowi BLooper nazwę name i wtedy go blokuje (przez wywołanie Lock()). priority jest wartością, która opisuje wielkość skupionej uwagi procesora na pętli komunikatu (chodzi tutaj o priorytet wątku, który decyduje o tym jak często dany wątek będzie wybierany przez planistę jądra systemu do przetwarzania przez procesor - przyp. tłum.), która będzie odbierać komunikaty gdy tylko rozpocznie działanie a portCapacity jest liczbą komunikatów które BLooper może przechowywać w "porcie komunikatu" (to nie jest kolejka komunikatu, jak wyjaśniono poniżej).

Po skonstruowaniu BLooper'a, musisz powiedzieć do niego Run(). Ponieważ obiekt jest zablokowany, Run() może być wywołane tylko z wątku który skonstruował obiekt. Jest on uprawniony do wywołania Run() z wnętrza implementacji konstruktora podklasy.

Priorytet

Zbiór wartości proiorytetu jest zdefinowany w kernel/OS.h; od najniższego do najwyższego, są to:

B_LOW_PRIORITY Dla wątków działających w tle, które nie powinny przerywać innych wątków.
B_NORMAL_PRIORITY Dla wszystkich zwykłych wątków, włącznie z wątkiem głównym.
B_DISPLAY_PRIORITY Dla wątków przypisanych do obiektów w interfejsie użytkownika, włączając wątki okien.
B_URGENT_DISPLAY_PRIORITY Dla wątków interfejsu, które zasługują na więej uwagi niż zwykłe okna.
B_REAL_TIME_DISPLAY_PRIORITY Dla wątków które wyświetlają animacje na ekranie.
B_URGENT_PRIORITY Dla wątków przetwarzająych obliczenia krytyczne pod względem czasowym.
B_REAL_TIME_PRIORITY Dla wątków sterujących procesami czasu rzeczywistego, które potrzebują nieskrępowanego dostępu do procesora(ów).

Pojemność portu

Komunikaty które są wysyłe do BLooper'a najpiewrw ukazują się w porcie (ten termin jest zdefiniowany w Kernel Kit) a wtedy są przemieszczane do BMessageQueue. Pojemność BMessageQueue jest faktycznie nieograniczona; pojemność portu jest ograniczona. Chociaż komunikaty są przemieszczane z portu do kolejki tak szybko jak to możwe, port może się przepełnić. Pełny port będzie blokował kolejnych nadawców komunikatów.

Domyśna pojemność portu (100) powinna być wystarczająca dla większości aplikacji ale możesz bawić się tym poprzez argument portCapacity.


~BLooper()

virtual ~BLooper()

Zwalnia kolejkę komunikatu i wszystkie nie obsłużone komunikaty i niszczy pętlę komunikatu. BHandler'y które miały być dodane do BLooper'a nie są niszczone ale obiekty BMessageFilter dodane jako wspólne filtry są niszczone.

Ogólnie, nigdynie powinieneś usuwać swoich obiektów typu BLooper poprzez delete: z wyjątkiem obiektu BApplication, BLooper'y są niszczone przez funkcję Quit().

Jeśi tworzysz klasę pochodną od BLooper'a, która używa wielokrotnego dziedziczenia, upewnij się, że pierwsza klasa w twojej mieszanej klasie dziedziczy z BLooper'a; inaczej nastąpi zawieszenie gdy spróbujesz zamknąć takie okno. Zdarza się to z powodu współdziałania pomiędzy wątkiem okna jak C++ usuwa obiekty klas z wielokrotnym dziedziczeniem. Inaczej mówiąc:

class myClass : public BLooper, public OtherClass {
...
};

jest bezpieczny, podczas gdy:
class myClass : public OtherClass, public BLooper {
...
};

nie jest.


Funkcje Statyczne


LooperForThread()

static BLooper *LooperForThread(thread_id thread)

Zwraca obiekt BLooper który zapoczątkował określony wątek thread lub NULL jeśli wątek nie należy do BLooper'a.


Funkcje Członkowskie


AddCommonFilterList(), RemoveCommonFilterList(), SetCommonFilterList(), CommonFilterList()

virtual void AddCommonFilter(BMessageFilter *filter)
virtual bool RemoveCommonFilter(BMessageFilter *filter)
virtual void SetCommonFilterList(BList *filters)
BList *CommonFilterList(void) const

Dla wszystkich oprócz CommonFilterList(), BLooper musi być zablokowany.

Te funkcje zarządzają listą BLooper'a zawierającą obiekty typu BMessageFilter. Filtry komunikatów są obiektami, które sprawdzają przychodzące komunikaty. W przypadku BLooper'a, każdy komunikat jest przepuszczany poprzez wszystkie filtry w liście przed przekazaniem go do DispatchMessage(). Kolejność filtró w liście jest okreśona. Patrz do klasę BMessageFilter aby zaczerpnąc szczegółów jak pracują filtry komunikatów.

AddCommonFilter() dodaje filter na koniec listy filtrów (jeśli trzeba tworzy pojemnik BList).

RemoveCommonFilter() usuwa filter z listy, ale go nie zwalnia. Zwraca true w przypadku sukcesu i false jeśli nie może znaleźć określonego filtra.

SetCommonFilterList() usuwa bieżącą listę filtrów i jej zawartość i zastępuje ją tą z parametru filters. Wszystkie elementy w liście filters muszą być wskaźnikami BMessageFilter. BLooper przejmuje na włsność wszystkie obiekty w liście filtrów filters, jak również samą listę filters. Jeśli filters jest równe NULL, bieżąca lisyta jest niszczona bez zamiany.

CommonFilterList() zwraca wskaźik do bieżącej listy. Moższ sprawdzać listę ale nie powinieneś jej modyfikować lub usuwać.


AddHandler(), RemoveHandler(), HandlerAt(), CountHandlers(), IndexOf()

void AddHandler(BHandler *handler)
bool RemoveHandler(BHandler *handler)
BHandler *HandlerAt(int32 index) const
int32 CountHandlers(void) const
int32 IndexOf(BHandler *handler) const

AddHandler() dodaje handler'a do listy BLooper'a zwierającej obiekty BHandler a RemoveHandler() usuwa go. Tylko BHandler'y, które zostały dodane do listy są uprawnione do odpowiadania na komunikaty które wysłał BLooper.

AddHandler() zawodzi jeśli handler już należy do BLooper'a; BHandler moż należeć do nie więej niż jednego BLooper na raz. Może on zmienić swoją przynależność od czasu do czasu ale musi być usunięty z jednego BLooper'a przed dodaniem go do kolejnego. RemoveHandler() zwraca true jeśli z sukcesem usunieBHandler'a z BLooper'a i false jeśli handler nienależy do tego BLooper'a w pierwszym miejscu.

AddHandler() wywołuje również funkcję SetNextHandler() handler'a do przypisania go BLooper'owi jako następnego domyślnego handler'a. RemoveHandler() wywołuje tą samą funkcję do ustawienia parametru handler nastęnego handler'a na wartość NULL.

HandlerAt() zwraca obiekt BHandler aktualnie ulokowany pod indeksem index w liście uprawnionych handlerów BLooper'a lub NULL jeśli indeks jest poza zakresem. Indeksy zaczynają sie od 0 a w liście nie ma przerw. CountHandlers() zwraca bieżącą liczbę obiektów w liście; ta ilość powinna być równa zawsze co najmniej 1, jako że lista automatycznie obejmuje samego BLooper'a. IndexOf() zwraca ikdeks określonego handler'a lub B_ERROR jeśli ten obiekt nie jest obecny w liście.

Do działania jakiejkolwiek z tych funkcji, BLooper musi być zablokowany.

Popatrz również do: BHandler::Looper(), BHandler::SetNextHandler(), PostMessage(), klasa BMessenger.


Archive()  patrz BArchivable::Archive()

CommonFilterList()  patrz AddCommonFilterList()
CountHandlers()  patrz AddHandler()
CountLockRequests()  patrz LockingThread()
CountLocks()  patrz LockingThread()


CurrentMessage(), DetachCurrentMessage()

BMessage *CurrentMessage(void) const
BMessage *DetachCurrentMessage(void)

Komunikat który BLooper przekazuje do swojego handler(ów) jest nazywany "bieżącym komunikatem." Te funkcje udostępniaja bieżący komunikat; są one bez znaczenia (zwracają NULL) gdy są wywołne spoza pętli przetwarzania komunikatów.

CurrentMessage() po prostu zwraca wskaźnik do bieżącego komunikatu bez oddziaływania na sam obiekt BMessage. Jest ot szczegónie przydatne do funkcji które odpowiadają na komunikaty systemowe (takie jak MouseDown() i ScreenChanged()), ale które nie są wysłne jako pełny obiekt BMessage, który zainicjował odpowiedź.

DetachCurrentMessage() usuwa bieżący komunikat z kolejki komunikatów i przekazuje jegoposiadanie do wywołującego; za usunięcie tego komunikatu jest odpowiedzialny wywołujący. Jest to przydatne jeśli chcesz opóźnić odpowiedź na komunikat bez męczenia BLooper'a. Ale bądź ostrożny - jeśli nadawca komunikatu będzie czekał na odpowiedź synchroniczną, odłaczenie komunikatu i przetrzymywanie go będzie blokować nadawcę.


Detach  patrz CurrentMessage()


DispatchMessage()

virtual void DispatchMessage(BMessage *message, BHandler *target)

DispatchMessage() jest centralną funkcją przetwarzania komunikatów BLooper'a. Jet ona wywoływana automatycznie gdy komunikaty przychodzą do kolejki looper'a, jedno wywołanie na komunikat. Nigdy sam nie wywołuj DispatchMessage().

Domyślna implementacja przekazuje komunikat message do handler'a przez wywołanie ostatniego MessageReceived():

target->MessageReceived(message);

Jedyny wyjątek jest tam gdzie message.what jest równe B_QUIT_REQUESTED a handler sam jest looper'em; w tym przypadku obiekt wywołuje swoją własną funkcję QuitRequested().

Możesz przesłonić (override) tą funkcję by wysłać komunikaty, które definuje lub rozpoznaje Twoja własna aplikacja.Wszystkie nieobsłużne komunkaty powinny być przekazane do wersji bazowej klasy jak zademonstrowano poniżej:

void MyLooper::DispatchMessage(BMessage *msg, BHandler *target)
{
   switch ( msg->what ) {
   case MY_MESSAGE1:
      ...
      break;
   case MY_MESSAGE2:
      ...
      break;
   default:
      baseClass::DispatchMessage(msg, target);
      break;
   }
}

Również zauważ, że nie musisz niszczyć message; jest on niszczony za Ciebie.

System blokuje BLooper'a przed wywołaniem DispatchMessage() i utrzymuje blokadę na czas trwania tej funkcji.


HandlerAt()  patrz AddHandler()
IndexOf()  patrz AddHandler()
IsLocked()  patrz LockingThread()


Lock(), LockWithTimeout(), Unlock()

bool Lock(void)
status_t LockWithTimeout(bigtime_t timeout)
void Unlock(void)

Lock() blokuje BLooper'a. Zamki są utrzymywane w kontekście wątku; dopóki BLooper jest zablokowany, żaden inny wątek nie może wywołać większości swoich ważnych funkcji (AddHandler(), DispatchMessage(), itd.).

Jeśli looper jest już zablokowany (przez jakiś inny wątek), funkcja Lock() blokuje się dotąd aż looper zostanie odblokowany (innymi słowy funkcja ta czeka na odblokowanie looper'a - przyp. tłum.). Natomiast do ustawienia czasu przerwy blokowania użyj funkcji LockWithTimeout() (czeka przez określoną ilość czasu - przyp. tłum.). timeout jest mierzony w mikrosekundach; jeśli jest równy 0, funkcja zwraca wartość natychmiast (z lub bez blokady); jeśli jest równy B_INFINITE_TIMEOUT, blokuje się ona bez ograniczeń czasowych.

Unlock() odblokowuje zablokowanego looper'a. Może być ona wywołana tylko przez wątek, który w danej chwili zamknął zamek.

Wywołania Lock()/LockWithTimeout() i Unlock() mogą byc zagnieżdżane, ale blokowanie i odblokowanie musi być zawsze zrównoważone. Pojedyncze wywołanie Unlock() nie cofnie serii wywołań Lock().

BHandler definiuje "sprytne" wersje tych funkcji, które znajdują looper handler'a i wtedy go blokują (lub go odblokowują) w operacji pseudoatomowej (czyli niepodzielnej, chodzi o niemożność wywłaszczenia wątku w którym ta operacja zachodzi, dopóki taka operacja się zakończy - przyp. tłum.) (patrz BHandler::LockLooper()). Zawsze powinieneś używać wersji BHandler'a , jeśli to możliwe, zamiast odzyskiwać looper handler'a i blokować go sam.

ZWRACANE KODY

Lock() zwraca true jeśli była zdolna zablokować looper'a lub jeśli jest on już zablokowany przez wątek wywołujący i false w przeciwnym razie.

LockWithTimeout() zwraca:


LockingThread(), IsLocked(), CountLocks(), CountLockRequests(), Sem()

thread_id LockingThread(void) const
bool IsLocked(void) const
int32 CountLocks(void) const
int32 CountLockRequests(void) const
sem_id Sem(void) const

Te funkcje moga być użyteczne podczas debugowania BLooper'a.

LockingThread() zwraca wątek, który aktualnie zablokował BLooper'a lub - 1 jeśli BLooper nie jest zablokowany.

IsLocked() zwraca true jeśli wywołany wątek zablokował BLooper'a (jeśli jest on wątkiem blokującym) i false jeśli nie zablokował (jeśli jakiś inny wątek jest wątkiem blokującym lub jeśli BLooper nie jest zablokowany).

CountLocks() zwraca ile razy wątek blokujący zablokował BLooper'a - liczba wywołań Lock() (lub LockWithTimeout()), które jeszcze nie zostały zrównoważone przez wywołanie odpowiednich Unlock().

CountLockRequests() zwraca liczbę wąktów próbujących obecnie zablokować BLooper'a. Ta liczba zawiera wątek, które obecnie dokonał blokady plus wszystkie wątki obecnie czekające na przejęcie go.

Sem() zwraca sem_id dla semafora, który używa BLooper do zaimplementowania mechanizmu zamka.

Popatrz również do: Lock()


LockWithTimeout()  patrz Lock()


MessageReceived()

virtual void MessageReceived(BMessage *message)

Wywołuje po prostu odzidziczoną funkcję. Dla bieżącego wydania implementacja tej funkcji BLooper'a nie wykonuje niczego znaczącego.

Popatrz również do: BHandler::MessageReceived()


MessageQueue()

BMessageQueue *MessageQueue(void) const

Zwraca kolejkę, która przechowuje komunikaty dostarczone do wątku BLooper'a. Rzadko będziesz potrzebował sprawdzać kolejkę komunikatów bezpośrednio; jest ona udostęniona więc możesz oszukać los przeglądając naprzód komunikaty.

Popatrz również do: klasa BMessageQueue.


PostMessage()

status_t PostMessage(BMessage *message)
status_t PostMessage(uint32 command)
status_t PostMessage(BMessage *message,
      BHandler *handler,
      BHandler *replyHandler = NULL)
status_t PostMessage(uint32 command,
      BHandler *handler,
      BHandler *replyHandler = NULL)

PostMessage() jest podobne do BMessenger::SendMessage(). Preferowana jest wersja BMessenger'a (jest to trochę bezpieczniejsze niż PostMessage()).

Umiszcza komunikat bliżej końca koleki komunikatów BLooper'a. Komunikat będzie przetwarzany przez DispatchMessage() gdy przejdzie do poczatku kolejki.

Komunikat może być pełnym obiektem BMessage (message) lub tylko stałą polecenia (command). W poprzednim przypadku komunikat jest kopiowany a adresat i pozostaje właścicielem argumentu, który może być usunięty jak tylko funkcja PostMessage() zwróci wartość. W drugim przypadku BMessage jest tworzony (i usuwany) za Ciebie.

handler jest wyznaczonym handler'em dla komunikatu i musi być częścią tego łańcucha handler'a BLooper'a. Jeśli handler jest (dosłownie) NULL, wyznaczony handler jest preferowanym handler'em BLooper'a w czasie wywoływania DispatchMessage(). W tej wersji PostMessage(), która nie ma argumentu handler, wyznaczony handler jest samym obiektem BLooper.

Odpowiada na komunikat dostarczony do replyHandler. Jeśli replyHandler nie jest określony, odpowiedzi są wysyłąne do be_app_messenger.

BLooper nigdy nie powinien wysyłać komunikatu do siebie samego z wnętrza swojego własnego wątku pętli komunikatu.

ZWRACANE KODY


PreferredHandler()  patrz SetPreferredHandler()


Quit()

virtual void Quit(void)

Wyłącza pętlę komunikatu (jeśli ona działa) i niszczy BLooper'a. Obiekt musi być zablokowany.

Kiedy jest wywoływana funkcja Quit() z wątku BLooper'a, pętla komunikatu jest natychmiast zatrzymywana a komunikaty w kolejce komunikatów są niszczone (nie będąc przetwarzane). Zauważ, że w tym przypadku, Quit() nie zwraca wartości odkąd wywoływany wątek został zniszczony.

Kiedy wywołano tą funkcję z kolejnego wątku, Quit() czeka dopóki wszystkie bieżące komunikaty w kolejce zostaną obsłużone zanim zniszczy ona pętlę komunikatu. Zwraca ona wartość po tym jak BLooper został zniszczony.

Jeśli opuszczasz BLooper'a z jakiegoś innego wątku, powinieneś wysłać obiektowi komunikat B_QUIT_REQUESTED zamiast bezpośrednio wywoływać Quit().


QuitRequested()

virtual bool QuitRequested(void)

Funkcja przechwytująca, która jest wywołana gdy BLooper odbiera komunikat B_QUIT_REQUESTED. Nigdy nie wywołuj tej funkcji bezpośrednio. Klasy pochodne implementują tę funkcję aby zwróciła true jeśli jeśli jest ona zdolna opuścić BLooper i false jeśli nie jest. Zauważ, że ta funkcja nie przeprowadza obecnie opuszczenia obiektu - robi to kod, który obsługuje komunikat B_QUIT_REQUESTED.

Domyślna implementacja funkcji QuitRequested() obiektu BLooper zawsze zwraca true.


RemoveCommonFilter()  patrz AddCommonFilterList()


Run()

virtual thread_id Run(void)

Zapoczątkowuje nowy wątek pętli komunikatu i uruchamia jego działanie. Run() oczekuje aby BLooper był zablokowany (tylko raz!) gdy jest ona wywoływana; odblokowuje ona obiekt przed zwróceniem wartości. Pamiętaj, że BLooper jest zablokowany gdy jest skonstruowany.

Wywołanie Run() na BLooper'ze, który już działa będzie Cię przerzucać do debugger'a.

ZWRACANE KODY


AddCommonFilter()


SetPreferredHandler(), PreferredHandler()

void SetPreferredHandler(BHandlerAddCommonFilter() *handler) const
BHandler *PreferredHandler(void)

Te funkcje ustawiają i zwracają preferowany handler BLooper'a - obiekt BHandler , który powinien obsłużyć komunikaty nie jest specjalnie adresowany do kolejnego BHandler'a.

Do wyznaczenia bieżącego preferowanego handler'a - jakikolwiek jest to obiekt - jako adresat komunikatu, przekazuje NULL do funkcji PostMessage() adresowanego handle'a lub konstruktora BMessenger'a.

Przekazanie lub wysłąnie komunikatu do preferowanego handler'a może być użyteczne. Na przykład, w Interface Kit, obiekty BWindow podają bieżący widok z ogniskiem jako preferowany handler. Jest to możliwe dla innych obiektów - takich jak BMenuItems i BButtons - do adresowania komunikatow do BView, któy ma obecnie ognisko, nie wiedząc który to może być widok. Na przykład, przez przekazanie komunikatów do preferowanego handler'a okna, pozycja menu "Cut" może upewnić się, że zawsze operuje na dowolnym widoku zawierającym bieżące zaznaczenie. Popatrz do rozdziału w Interface Kit aby zdobyć informacje o oknach, widokach i roli ogniska widoku.

Domyślnie, BLooper'y nie mają preferowanego handler'a; dopóki nie zostanie on ustawiony, PreferredHandler() zwraca NULL. Zauważ jednak, że komunikaty adresowane do preferowanego handler'a są rozsyłane do BLooper'a zawsze gdy preferowany handler jest równy NULL. Innymi słowy, BLooper działa jak domyślny preferowany handler, chociaż komunikat domyślny jest formalnie równy NULL.

Popatrz również do: BControl::SetTarget() i BMenuItem::SetTarget() w Interface Kit, PostMessage()


Thread(), Team()

thread_id Thread(void) const
team_id Team(void) const

Te funkcje identyfikją wątek który uruchomiłpętlę komunikatu i zespół do którego on należy. Thread() zwraca B_ERROR jeśli Run() nie został jeszcze wywołany do zapoczątkowania wątku i rozpoczęcia pętli. Team() zawsze zwraca team_id aplikacji.


Unlock()  patrz Lock()


Stałe


B_LOOPER_PORT_DEFAULT_CAPACITY

#define B_LOOPER_PORT_DEFAULT_CAPACITY 100

Domyślna wartość portu, która przechowuje nadchodzace komunikaty zanim zostaną one umieszczone w BMessageQueue BLooper'a. Pojemność jest ustawiana w konstruktorze BLooper'a.


Be Book Application Kit Application Kit Indeks

Be Book,
...w ślicznym HTML...
dla BeOS wydanie 5

Copyright © 2000 Be, Inc. Wszelkie prawa zastrzeżone.