Wielowątkowość: Porady dotyczące programowania MFC
Aplikacje wielowątkowa wymagają ściślejszej opieki niż aplikacje jednowątkowe w celu zapewnienia, że operacje występują w zamierzonej kolejności, a wszystkie dane, do których uzyskuje się dostęp przez wiele wątków, nie są uszkodzone. W tym temacie opisano techniki unikania potencjalnych problemów podczas programowania wielowątków aplikacji przy użyciu biblioteki MFC (Microsoft Foundation Class).
Uzyskiwanie dostępu do obiektów z wielu wątków
Obiekty MFC nie są bezpieczne wątkowo. Dwa oddzielne wątki nie mogą manipulować tym samym obiektem, chyba że używasz klas synchronizacji MFC i/lub odpowiednich obiektów synchronizacji Win32, takich jak sekcje krytyczne. Aby uzyskać więcej informacji o sekcjach krytycznych i innych powiązanych obiektach, zobacz Synchronizacja w zestawie Windows SDK.
Biblioteka klas używa sekcji krytycznych wewnętrznie do ochrony globalnych struktur danych, takich jak te używane przez alokację pamięci debugowania.
Uzyskiwanie dostępu do obiektów MFC z wątków innych niż MFC
Jeśli masz aplikację wielowątkową, która tworzy wątek w sposób inny niż używanie obiektu CWinThread , nie możesz uzyskać dostępu do innych obiektów MFC z tego wątku. Innymi słowy, jeśli chcesz uzyskać dostęp do dowolnego obiektu MFC z wątku pomocniczego, musisz utworzyć ten wątek przy użyciu jednej z metod opisanych w temacie Wielowątkowa: Tworzenie wątków interfejsu użytkownika lub wielowątkowość: tworzenie wątków procesu roboczego. Te metody są jedynymi, które umożliwiają bibliotece klas inicjowanie zmiennych wewnętrznych niezbędnych do obsługi aplikacji wielowątku.
Mapy dojścia systemu Windows
Ogólnie rzecz biorąc, wątek może uzyskiwać dostęp tylko do utworzonych obiektów MFC. Dzieje się tak, ponieważ tymczasowe i trwałe mapy obsługi systemu Windows są przechowywane w magazynie lokalnym wątku, aby zapewnić ochronę przed równoczesnym dostępem z wielu wątków. Na przykład wątek procesu roboczego nie może wykonać obliczeń, a następnie wywołać funkcję składową dokumentu UpdateAllViews
, aby okna zawierające widoki na nowych danych zostały zmodyfikowane. Nie ma to żadnego wpływu, ponieważ mapa z CWnd
obiektów do HWND jest lokalna dla wątku podstawowego. Oznacza to, że jeden wątek może mieć mapowanie z uchwytu systemu Windows na obiekt C++, ale inny wątek może mapować ten sam uchwyt na inny obiekt C++. Zmiany wprowadzone w jednym wątku nie zostaną odzwierciedlone w drugim.
Istnieje kilka sposobów obejścia tego problemu. Pierwszym z nich jest przekazanie poszczególnych dojść (takich jak HWND), a nie obiektów języka C++ do wątku roboczego. Następnie wątek procesu roboczego dodaje te obiekty do swojej tymczasowej mapy, wywołując odpowiednią FromHandle
funkcję składową. Można również dodać obiekt do stałej mapy wątku, wywołując Attach
metodę , ale należy to zrobić tylko wtedy, gdy zagwarantowano, że obiekt będzie istniał dłużej niż wątek.
Inną metodą jest utworzenie nowych komunikatów zdefiniowanych przez użytkownika odpowiadających różnym zadaniam, które będą wykonywać wątki robocze i publikować te komunikaty w głównym oknie aplikacji przy użyciu polecenia ::PostMessage
. Ta metoda komunikacji jest podobna do dwóch różnych aplikacji zbieżnych z tą różnicą, że oba wątki są wykonywane w tej samej przestrzeni adresowej.
Aby uzyskać więcej informacji na temat obsługi map, zobacz Technical Note 3 (Uwaga techniczna 3). Aby uzyskać więcej informacji na temat magazynu lokalnego wątku, zobacz Magazyn lokalny wątku i Używanie magazynu lokalnego wątku w zestawie Windows SDK.
Komunikacja między wątkami
MFC udostępnia szereg klas, które umożliwiają wątkom synchronizowanie dostępu do obiektów w celu zachowania bezpieczeństwa wątków. Użycie tych klas opisano w temacie Wielowątkowość: Jak używać klas synchronizacji i wielowątkowość: kiedy należy używać klas synchronizacji. Aby uzyskać więcej informacji na temat tych obiektów, zobacz Synchronizacja w zestawie Windows SDK.