Wielowątkowość: tworzenie wątków roboczych
Wątek roboczy jest powszechnie używany do obsługi zadania w tle, na które użytkownik nie powinien zaczekać, aby kontynuować korzystanie z aplikacji.Zadania, takie jak ponowne obliczenie i drukowanie w tle są dobrym przykładem wątków roboczych.Ten temat wyszczególnia kroki konieczne do utworzenia ciągu roboczego.Tematy obejmują:
Rozpoczęcie wątku
Implementacja funkcji kontroli
Przykład
Tworzenie wątku roboczego jest stosunkowo prostym zadaniem.Tylko dwa kroki są wymagane, aby wątek działa: wykonywanie funkcji kontrolowania oraz rozpoczęcie wątku.Nie jest konieczne, aby wyprowadzić klasę z CWinThread.Możesz derywować klasę, jeżeli potrzebujesz specjalnej wersji CWinThread, ale nie jest to wymagane dla większości prostych wątków roboczych.Można użyć CWinThread bez modyfikacji.
Rozpoczęcie wątku
Istnieją dwie przeciążone wersje AfxBeginThread: jedna, która tworzy tylko wątki robocze oraz jedna, która tworzy wątki interfejsu użytkownika oraz wątki robocze.Aby rozpocząć wykonywanie ciągu roboczego z użyciem pierwszego przeciążenia, wywołaj AfxBeginThread, podając następujące informacje:
Adres początkowy funkcji kontroli.
Parametr do przekazania do funkcji kontroli.
(Opcjonalnie) Żądany priorytet wątku.Ustawieniem domyślnym jest priorytet normalny.Aby uzyskać więcej informacji dotyczących dostępnych poziomów priorytetu, zobacz SetThreadPriority w Windows SDK.
(Opcjonalnie) Żądany rozmiar stosu dla wątku.Rozmiar stosu jest domyślnie taki sam jak rozmiar stosu wątku tworzącego.
(Opcjonalnie) CREATE_SUSPENDED Jeśli chcesz, aby wątek był utworzony w stanie wstrzymania.Wartość domyślna jest równa 0 lub wątek uruchamia się normalnie.
(Opcjonalnie) Atrybuty pożądanych zabezpieczeń.Wartością domyślną jest taki sam dostęp jak wątku nadrzędnego.Aby uzyskać więcej informacji dotyczących formatu informacji o zabezpieczeniach, zobacz SECURITY_ATTRIBUTES w Windows SDK.
AfxBeginThread Tworzy i inicjuje CWinThread obiekt dla ciebie, uruchomia go i zwraca jego adres, tak abyś mógł odwoływać się do niego później.Kontrole są wprowadzane w trakcie trwania procedury, żeby upewnić się, że wszystkie obiekty są zdelokowane poprawnie w przypadku gdy jakakolwiek część stworzenia się nie powiedzie.
Implementacja funkcji kontroli
Funkcja kontrolowania definiuje wątek.Po wpisaniu tej funkcji, rozpoczyna się wątek, a kiedy wychodzi, wątek się kończy.Ta funkcja powinna mieć poniższy prototyp:
UINT MyControllingFunction( LPVOID pParam );
Parametr ma pojedynczą wartość.Wartość otrzymywana przez funkcję w tym parametrze to wartość, która została przekazana konstruktorowi kiedy został utworzony obiekt wątku.Funkcja kontroli może interpretować tę wartość w jakikolwiek sposób.Może być traktowane jako wartość skalarna lub wskaźnika do struktury zawierającej wiele parametrów, lub można go zignorować.Jeśli parametr odnosi się do struktury, struktura może służyć nie tylko do przekazywania danych od elementu wywołującego do wątku, ale także do przekazywania danych z powrotem od wątku do obiektu wywołującego.Jeśli korzystasz z takiej struktury do przekazywania danych z powrotem do obiektu wywołującego, wątek musi powiadomić obiekt wywołujący, gdy wyniki są gotowe.Informacje dotyczące komunikacji między wątkiem roboczym a wywołującym – zobacz: Wielowątkowość: porady dotyczące programowania.
Kiedy funkcja kończy, powinna zwrócić wartość UINT oznaczającą powód zakończenia.Typowo, ten kod wyjścia to 0, które oznacza sukces, a inne wartości oznaczają różne typy błędów.Zależy to wyłącznie od implementacji.Niektóre wątki mogą utrzymywać liczniki użycia obiektów i zwracać bieżącą liczbę zastosowań tego obiektu.Aby zobaczyć jak aplikacje mogą odzyskiwać tę wartość, zobacz Wielowątkowość: kończenie wątków.
Istnieje kilka ograniczeń związanych z wykonywanymi czynnościami w wielowątkowym programie napisanym z biblioteką MFC>Opis tych ograniczeń i inne porady dotyczące korzystania z wątków – zobacz: Wielowątkowość: Porady dotyczące programowania.
Przykład funkcji sterowania
Poniższy przykład pokazuje jak zdefiniować funkcję kontroli i używać jej z innej części programu.
UINT MyThreadProc( LPVOID pParam )
{
CMyObject* pObject = (CMyObject*)pParam;
if (pObject == NULL ||
!pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
return 1; // if pObject is not valid
// do something with 'pObject'
return 0; // thread completed successfully
}
// inside a different function in the program
.
.
.
pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
.
.
.