Niedawno próbowałem uzyskać dostęp do pola tekstowego z wątku (innego niż wątek interfejsu użytkownika) i został zgłoszony wyjątek. Mówił coś o tym, że „kod nie jest bezpieczny dla wątków”, więc napisałem delegata (pomógł przykład z MSDN) i wywołałem go.
Ale mimo to nie bardzo rozumiałem, dlaczego cały dodatkowy kod był potrzebny.
Aktualizacja: Czy jeśli sprawdzę, napotkam jakieś poważne problemy
Controls.CheckForIllegalCrossThread..blah =true
multithreading
thread-safety
definition
Vivek Bernard
źródło
źródło
Race-Condition
Odpowiedzi:
Eric Lippert zamieścił fajny wpis na blogu zatytułowany Co to jest to, co nazywasz „bezpiecznym wątkiem”? o definicji bezpieczeństwa nici, znalezionej w Wikipedii.
3 ważne rzeczy wyodrębnione z linków:
Zdecydowanie warte przeczytania!
źródło
Mówiąc najprościej, ochrona wątków oznacza, że dostęp z wielu wątków jest bezpieczny. Kiedy używasz wielu wątków w programie i każdy z nich próbuje uzyskać dostęp do wspólnej struktury danych lub lokalizacji w pamięci, może się zdarzyć kilka złych rzeczy. Więc dodajesz dodatkowy kod, aby zapobiec tym złym rzeczom. Na przykład, jeśli dwie osoby pisały ten sam dokument w tym samym czasie, druga zapisywana osoba nadpisze pracę pierwszej osoby. Aby zapewnić bezpieczeństwo wątku, musisz zmusić osobę 2 do czekania, aż osoba 1 wykona swoje zadanie, zanim zezwolisz osobie 2 na edycję dokumentu.
źródło
Wikipedia zawiera artykuł na temat bezpieczeństwa wątków.
Ta strona z definicjami (musisz pominąć reklamę - przepraszam) definiuje ją w ten sposób:
Wątek to ścieżka wykonywania programu. Program z pojedynczym wątkiem będzie miał tylko jeden wątek, więc ten problem nie występuje. Praktycznie wszystkie programy GUI mają wiele ścieżek wykonywania, a tym samym wątków - są co najmniej dwa, jeden do przetwarzania wyświetlania GUI i obsługi danych wejściowych użytkownika, a co najmniej jeden do faktycznego wykonywania operacji programu.
Dzieje się tak, aby interfejs użytkownika nadal reagował, gdy program działa, odciążając dowolny długo działający proces do wszystkich wątków niezwiązanych z interfejsem użytkownika. Te wątki mogą być tworzone raz i istnieć przez cały czas trwania programu lub po prostu zostać utworzone, gdy są potrzebne, i zniszczone po zakończeniu.
Ponieważ te wątki często będą musiały wykonywać typowe czynności - operacje wejścia / wyjścia dysku, wyświetlanie wyników na ekranie itp. - te części kodu będą musiały być napisane w taki sposób, aby mogły obsługiwać wywołania z wielu wątków, często w o tym samym czasie. Będzie to obejmować takie rzeczy, jak:
źródło
Po prostu bezpieczeństwo wątków oznacza, że metoda lub instancja klasy może być używana przez wiele wątków jednocześnie bez żadnych problemów.
Rozważ następującą metodę:
Teraz wątek A i wątek B chciałyby wykonać AddOne (). ale A zaczyna pierwszy i czyta wartość myInt (0) do tmp. Teraz z jakiegoś powodu planista decyduje się zatrzymać wątek A i odroczyć wykonanie do wątku B. Wątek B odczytuje teraz również wartość myInt (nadal 0) do swojej własnej zmiennej tmp. Wątek B kończy całą metodę, więc na końcu myInt = 1. Zwracane jest 1. Teraz kolej na wątek A. Wątek A jest kontynuowany. I dodaje 1 do tmp (tmp wynosi 0 dla wątku A). A następnie zapisuje tę wartość w myInt. myInt to znowu 1.
Więc w tym przypadku metoda AddOne została wywołana dwa razy, ale ponieważ metoda nie została zaimplementowana w sposób bezpieczny dla wątków, wartość myInt nie wynosi 2, jak oczekiwano, ale 1, ponieważ drugi wątek odczytuje zmienną myInt przed zakończeniem pierwszego wątku aktualizowanie.
Tworzenie metod bezpiecznych dla wątków jest bardzo trudne w nietrywialnych przypadkach. Istnieje kilka technik. W Javie możesz oznaczyć metodę jako zsynchronizowaną, co oznacza, że tylko jeden wątek może wykonywać tę metodę w danym czasie. Pozostałe wątki czekają w kolejce. To sprawia, że wątek metody jest bezpieczny, ale jeśli jest dużo pracy do wykonania w metodzie, to marnuje to dużo miejsca. Inną techniką jest „oznaczenie tylko niewielkiej części metody jako zsynchronizowanej”tworząc blokadę lub semafor i blokując tę małą część (zwykle nazywaną sekcją krytyczną). Istnieją nawet metody, które są zaimplementowane jako bezpieczne dla wątków bez blokowania, co oznacza, że są zbudowane w taki sposób, że wiele wątków może biegać przez nie w tym samym czasie, nigdy nie powodując problemów, może tak być w przypadku, gdy metoda wykonuje jedno wywołanie atomowe. Wywołania atomowe to wywołania, których nie można przerwać i mogą być wykonywane tylko przez jeden wątek naraz.
źródło
W prawdziwym świecie przykładem dla laika jest
Załóżmy, że masz konto bankowe w bankowości internetowej i mobilnej, a Twoje konto ma tylko 10 USD. Dokonałeś przelewu środków na inne konto za pomocą bankowości mobilnej, aw międzyczasie robiłeś zakupy online, korzystając z tego samego konta bankowego. Jeśli to konto bankowe nie jest bezpieczne dla wątków, wówczas bank pozwala na wykonanie dwóch transakcji jednocześnie, a następnie bank zbankrutuje.
Threadsafe oznacza, że stan obiektu nie zmienia się, jeśli jednocześnie wiele wątków próbuje uzyskać dostęp do obiektu.
źródło
Więcej wyjaśnień można znaleźć w książce „Java Concurrency in Practice”:
źródło
Moduł jest bezpieczny dla wątków, jeśli gwarantuje, że może zachować niezmienniki w obliczu użycia wielowątkowego i współbieżnego.
W tym przypadku moduł może być strukturą danych, klasą, obiektem, metodą / procedurą lub funkcją. Zasadniczo fragment kodu i powiązane dane.
Gwarancja może być potencjalnie ograniczona do określonych środowisk, takich jak określona architektura procesora, ale musi obowiązywać dla tych środowisk. Jeśli nie ma wyraźnego rozgraniczenia środowisk, zwykle zakłada się, że dla wszystkich środowisk obowiązuje możliwość skompilowania i wykonania kodu.
Moduły niebezpieczne dla wątków mogą działać poprawnie w wielowątkowym i współbieżnym użyciu, ale często jest to bardziej kwestią szczęścia i zbiegów okoliczności niż starannego projektowania. Nawet jeśli jakiś moduł nie zepsuje się dla ciebie, może się zepsuć po przeniesieniu do innego środowiska.
Błędy wielowątkowe są często trudne do debugowania. Niektóre z nich zdarzają się sporadycznie, inne przejawiają się agresywnie - to również może być specyficzne dla środowiska. Mogą objawiać się jako subtelnie błędne wyniki lub impas. Mogą zepsuć struktury danych w nieprzewidywalny sposób i spowodować pojawienie się innych pozornie niemożliwych błędów w innych odległych częściach kodu. Może to być bardzo specyficzne dla aplikacji, więc trudno jest podać ogólny opis.
źródło
Bezpieczeństwo nici : program bezpieczny wątkowo chroni dane przed błędami spójności pamięci. W programie wielowątkowym program bezpieczny dla wątków nie powoduje żadnych skutków ubocznych z wieloma operacjami odczytu / zapisu z wielu wątków na tych samych obiektach. Różne wątki mogą udostępniać i modyfikować dane obiektu bez błędów spójności.
Bezpieczeństwo wątków można osiągnąć, korzystając z zaawansowanego interfejsu API współbieżności. Ta strona dokumentacji zawiera dobre konstrukcje programistyczne do osiągnięcia bezpieczeństwa wątków.
Obiekty blokujące obsługują idiomy blokowania, które upraszczają wiele współbieżnych aplikacji.
Wykonawcy definiują interfejs API wysokiego poziomu do uruchamiania wątków i zarządzania nimi. Implementacje modułu wykonawczego dostarczane przez java.util.concurrent zapewniają zarządzanie pulą wątków odpowiednie dla aplikacji na dużą skalę.
Kolekcje współbieżne ułatwiają zarządzanie dużymi zbiorami danych i mogą znacznie zmniejszyć potrzebę synchronizacji.
Zmienne atomowe mają funkcje, które minimalizują synchronizację i pomagają uniknąć błędów spójności pamięci.
ThreadLocalRandom (w JDK 7) zapewnia wydajne generowanie liczb pseudolosowych z wielu wątków.
Zobacz pakiety java.util.concurrent i java.util.concurrent.atomic dla innych konstrukcji programistycznych.
źródło
Oczywiście pracujesz w środowisku WinForms. Kontrolki WinForms wykazują powinowactwo wątków, co oznacza, że wątek, w którym zostały utworzone, jest jedynym wątkiem, którego można użyć do uzyskania do nich dostępu i aktualizacji. Dlatego w witrynie MSDN i innych miejscach znajdziesz przykłady pokazujące, jak skierować wywołanie z powrotem do głównego wątku.
Normalną praktyką WinForm jest posiadanie jednego wątku, który jest przeznaczony do pracy z interfejsem użytkownika.
źródło
Uważam, że koncepcja http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 jest tym, co zwykle uważam za niebezpieczne wątkowanie, które ma miejsce, gdy metoda ma i polega na efekcie ubocznym, takim jak zmienna globalna.
Na przykład widziałem kod, który sformatował liczby zmiennoprzecinkowe w łańcuchy, jeśli dwa z nich są uruchomione w różnych wątkach, globalna wartość decimalSeparator może zostać trwale zmieniona na „.”
źródło
Aby zrozumieć bezpieczeństwo wątków, przeczytaj poniższe sekcje :
źródło