Wielowątkowość: tworzenie wątków procesów roboczych w MFC

Wątek procesu roboczego jest często używany do obsługi zadań w tle, których użytkownik nie powinien czekać, aż będzie nadal korzystać z aplikacji. Zadania takie jak ponowne obliczanie i drukowanie w tle są dobrymi przykładami wątków roboczych. W tym temacie opisano kroki niezbędne do utworzenia wątku roboczego. Tematy obejmują:

Tworzenie wątku roboczego jest stosunkowo prostym zadaniem. Do uruchomienia wątku wymagane są tylko dwa kroki: zaimplementowanie funkcji sterującej i uruchomienie wątku. Nie jest konieczne uzyskanie klasy z CWinThread. Klasę można uzyskać, jeśli potrzebujesz specjalnej CWinThreadwersji , ale nie jest wymagana w przypadku większości prostych wątków roboczych. Można użyć CWinThread bez modyfikacji.

Uruchamianie wątku

Istnieją dwie przeciążone wersje AfxBeginThread: jedna, która może tworzyć tylko wątki robocze, i jeden, który może tworzyć zarówno wątki interfejsu użytkownika, jak i wątki robocze. Aby rozpocząć wykonywanie wątku roboczego przy użyciu pierwszego przeciążenia, wywołaj element AfxBeginThread, podając następujące informacje:

  • Adres funkcji sterującej.

  • Parametr, który ma zostać przekazany do funkcji sterującej.

  • (Opcjonalnie) Żądany priorytet wątku. Wartość domyślna to normalny priorytet. Aby uzyskać więcej informacji na temat dostępnych poziomów priorytetu, zobacz SetThreadPriority w zestawie Windows SDK.

  • (Opcjonalnie) Żądany rozmiar stosu dla wątku. Wartość domyślna to ten sam stos rozmiaru co wątek tworzenia.

  • (Opcjonalnie) CREATE_SUSPENDED, jeśli chcesz, aby wątek został utworzony w stanie wstrzymania. Wartość domyślna to 0 lub zwykle uruchamiać wątek.

  • (Opcjonalnie) Żądane atrybuty zabezpieczeń. Wartość domyślna to ten sam dostęp co wątek nadrzędny. Aby uzyskać więcej informacji na temat formatu tych informacji o zabezpieczeniach, zobacz SECURITY_ATTRIBUTES w zestawie Windows SDK.

AfxBeginThread Tworzy i inicjuje CWinThread obiekt dla Użytkownika, uruchamia go i zwraca jego adres, aby można było odwoływać się do niego później. Kontrole są wykonywane w całej procedurze, aby upewnić się, że wszystkie obiekty są prawidłowo cofnięte, jeśli jakakolwiek część tworzenia zakończy się niepowodzeniem.

Implementowanie funkcji sterującej

Funkcja kontrolująca definiuje wątek. Po wprowadzeniu tej funkcji wątek zostanie uruchomiony, a po jego zakończeniu wątek zakończy się. Ta funkcja powinna mieć następujący prototyp:

UINT MyControllingFunction( LPVOID pParam );

Parametr jest pojedynczą wartością. Wartość odbierana przez funkcję w tym parametrze jest wartością przekazaną do konstruktora podczas tworzenia obiektu wątku. Funkcja kontrolująca może interpretować tę wartość w dowolny sposób. Może być traktowana jako wartość skalarna lub wskaźnik do struktury zawierającej wiele parametrów lub można ją zignorować. Jeśli parametr odwołuje się do struktury, struktura może służyć nie tylko do przekazywania danych z obiektu wywołującego do wątku, ale także do przekazywania danych z powrotem z wątku do obiektu wywołującego. Jeśli używasz takiej struktury do przekazywania danych z powrotem do obiektu wywołującego, wątek musi powiadomić obiekt wywołujący, gdy wyniki będą gotowe. Aby uzyskać informacje o komunikacji z wątku roboczego do obiektu wywołującego, zobacz Wielowątkowa obsługa: programowanie Wskazówki.

Po zakończeniu działania funkcji powinna zwrócić wartość UINT wskazującą przyczynę zakończenia. Zazwyczaj ten kod zakończenia wynosi 0, aby wskazać powodzenie z innymi wartościami wskazującymi różne typy błędów. Jest to wyłącznie zależne od implementacji. Niektóre wątki mogą utrzymywać liczbę użycia obiektów i zwracać bieżącą liczbę zastosowań tego obiektu. Aby zobaczyć, jak aplikacje mogą pobrać tę wartość, zobacz Multithreading: Zakończenie wątków.

Istnieją pewne ograniczenia dotyczące tego, co można zrobić w wielowątkowym programie napisanym za pomocą biblioteki MFC. Opisy tych ograniczeń i innych wskazówek dotyczących używania wątków można znaleźć w temacie Multithreading: Programming Wskazówki (Multithreading: Programming Wskazówki).

Przykład funkcji kontrolującej

W poniższym przykładzie pokazano, jak zdefiniować funkcję kontrolującą i użyć 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);
.
.
.

Co chcesz dowiedzieć się więcej?

Zobacz też

Wielowątkowość z C++ i MFC