Udostępnij za pośrednictwem


Buforowanie wątków

Istnieje wiele aplikacji, które tworzą wątki spędzające dużo czasu w stanie uśpienia, czekając na wystąpienie zdarzenia. Inne wątki mogą przechodzić w stan uśpienia i być okresowo wybudzane, aby sprawdzać informacje o zmianach lub aktualizacji stanu. Pulowanie wątków pozwala na bardziej wydajne korzystanie z wątków, udostępniając aplikacji pulę wątków roboczych zarządzanych przez system. Co najmniej jeden wątek monitoruje stan wszystkich operacji oczekiwania w kolejce do puli wątków. Po zakończeniu operacji oczekiwania wątek roboczy z puli wątków wykonuje odpowiednią funkcję wywołania zwrotnego.

W tym temacie opisano oryginalne API dla puli wątków. Interfejs API puli wątków wprowadzony w systemie Windows Vista jest prostszy, bardziej niezawodny, ma lepszą wydajność i zapewnia większą elastyczność dla deweloperów. Aby uzyskać informacje na temat bieżącego interfejsu API puli wątków, zobacz Thread Pools.

Możesz również umieścić elementy robocze w kolejce, które nie są powiązane z operacją oczekiwania do puli wątków. Aby zażądać obsługi elementu roboczego przez wątek w puli wątków, wywołaj funkcję QueueUserWorkItem. Ta funkcja przyjmuje parametr do funkcji, która zostanie wywołana przez wątek wybrany z puli wątków. Nie ma możliwości anulowania elementu roboczego po jego zakolejkowaniu.

Timery kolejki i zarejestrowane operacje oczekiwania również używają puli wątków. Ich funkcje wywołania zwrotnego są kolejkowane do puli wątków. Możesz również użyć funkcji BindIoCompletionCallback, aby opublikować operacje we/wy asynchroniczne. Po zakończeniu operacji we/wy wywołanie zwrotne jest wykonywane przez wątek puli wątków.

Pula wątków jest tworzona przy pierwszym wywołaniu QueueUserWorkItem lub BindIoCompletionCallback, lub gdy czasomierz kolejki lub zarejestrowana operacja oczekiwania kolejkuje funkcję wywołania zwrotnego. Domyślnie liczba wątków, które można utworzyć w puli wątków, wynosi około 500. Każdy wątek używa domyślnego rozmiaru stosu i jest uruchamiany z domyślnym priorytetem.

Istnieją dwa typy wątków roboczych w puli wątków: I/O i nie-I/O. Wątek I/O jest wątkiem, który czeka w stanie oczekiwania z możliwością alertu. Elementy robocze są kolejkowane do wątków roboczych I/O jako asynchroniczne wywołania procedur (APC). Powinieneś zakolejkować element roboczy do wątku roboczego I/O, jeśli powinien zostać wykonany w wątku, który czeka w stanie oczekiwania na powiadomienie.

Wątek roboczy nieobsługujący operacji we/wy czeka na portach zakończenia operacji we/wy. Korzystanie z wątków nie-I/O jest bardziej wydajne od wątków I/O. W związku z tym należy używać wątków roboczych innych niż we/wy, gdy jest to możliwe. Zarówno wątki robocze we/wy, jak i te inne niż we/wy, nie kończą działania, jeśli istnieją oczekujące asynchroniczne żądania we/wy. Elementy robocze, które inicjują asynchroniczne żądania zakończenia operacji wejścia-wyjścia, mogą używać obu typów wątków. Należy jednak unikać wysyłania asynchronicznych żądań ukończenia operacji wejścia/wyjścia w wątkach roboczych, które nie obsługują operacji we/wy, jeśli ukończenie może zająć dużo czasu.

Aby można było używać puli wątków, elementy robocze i wszystkie wywoływane przez nie funkcje muszą być bezpieczne dla puli wątków. Bezpieczna funkcja nie zakłada, że wątek wykonujący go jest dedykowanym lub trwałym wątkiem. Ogólnie rzecz biorąc, powinno się unikać stosowania pamięci lokalnej dla wątku lub wykonywania asynchronicznego wywołania, które wymaga stałego wątku, na przykład funkcji RegNotifyChangeKeyValue. Jednak takie funkcje można wywoływać w dedykowanym wątku (utworzonym przez aplikację) lub umieścić w kolejce do trwałego wątku roboczego (przy użyciu QueueUserWorkItem z opcją WT_EXECUTEINPERSISTENTTHREAD).

I/O z możliwością generowania alertów

Asynchroniczne wywołania procedur

porty zakończenia we/wy

pule wątków