Co oznacza kod "bezpieczny dla wątków"?

Czy to znaczy, że dwa wątki nie mogą jednocześnie zmieniać danych? A może to oznacza, że dany segment kodu będzie działał z przewidywalnymi wynikami, gdy uruchomi go więcej niż jeden wątek?

Author: darth_coder, 2008-11-04

15 answers

Z Wikipedii:

Thread safety to pojęcie programowania komputerowego stosowane w kontekście programów wielowątkowych. Fragment kodu jest bezpieczny dla wątków, jeśli działa poprawnie podczas jednoczesnego wykonywania przez wiele wątków. W szczególności musi on zaspokoić potrzebę dostępu wielu wątków do tych samych udostępnionych danych oraz potrzebę dostępu do udostępnionych danych tylko przez jeden wątek w danym momencie.

...

Istnieje kilka sposobów na osiągnij bezpieczeństwo wątku:

Re-entrancy

pisanie kodu w taki sposób, że może on być częściowo wykonany przez jedno zadanie, przywrócony przez inne zadanie, a następnie wznowiony z pierwotnego zadania. Wymaga to zapisywania informacji o stanie w zmiennych lokalnych dla każdego zadania, zwykle na jego stosie, zamiast w zmiennych statycznych lub globalnych.

Wzajemne wykluczenie

Dostęp do udostępnionych danych jest serializowany za pomocą mechanizmów, które zapewniają tylko jeden wątek odczytuje lub zapisuje udostępnione dane w dowolnym momencie. Wymagana jest duża ostrożność, jeśli fragment kodu uzyskuje dostęp do wielu udostępnionych fragmentów danych-problemy obejmują warunki rasowe, blokady, blokady życia, głód i różne inne choroby wymienione w wielu podręcznikach systemów operacyjnych.

Thread-local storage

zmienne są zlokalizowane tak, że każdy wątek ma własną prywatną kopię. Zmienne te zachowują swoje wartości w podprogramie i innych granicach kodu, oraz są bezpieczne dla wątków, ponieważ są lokalne dla każdego wątku, nawet jeśli kod, który do nich uzyskuje dostęp, może być reentrant.

Operacje atomowe

udostępniane dane są dostępne za pomocą operacji atomowych, które nie mogą być przerwane przez inne wątki. Zwykle wymaga to użycia specjalnych instrukcji w języku maszynowym, które mogą być dostępne w bibliotece uruchomieniowej. Ponieważ operacje są atomowe, udostępnione dane są zawsze przechowywane w prawidłowym stanie, bez względu na inne wątki mają do niego dostęp. Operacje atomowe stanowią podstawę wielu mechanizmów blokujących wątki.

Czytaj więcej:

Http://en.wikipedia.org/wiki/Thread_safety


 205
Author: Blauohr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 14:29:56

Thread-safe code to kod, który będzie działał, nawet jeśli wiele wątków wykonuje go jednocześnie.

Http://mindprod.com/jgloss/threadsafe.html

 68
Author: Marek Blotny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 12:17:28

Bardziej pouczające pytanie brzmi: co sprawia, że kod nie jest bezpieczny dla wątków - a odpowiedź brzmi: istnieją cztery warunki, które muszą być prawdziwe... Wyobraź sobie następujący kod (i jest to tłumaczenie w języku maszynowym)

totalRequests = totalRequests + 1
MOV EAX, [totalRequests]   // load memory for tot Requests into register
INC EAX                    // update register
MOV [totalRequests], EAX   // store updated value back to memory
  1. pierwszym warunkiem jest to, że istnieją miejsca pamięci, które są dostępne z więcej niż jednego wątku. Zazwyczaj te lokalizacje są zmiennymi globalnymi/statycznymi lub są pamięcią sterty osiągalną ze zmiennych globalnych / statycznych. Każdy wątek otrzymuje własną ramkę stosu dla zmienne lokalne o zasięgu funkcji/metody, więc te zmienne lokalne o zasięgu funkcji / metody, otoh, (które znajdują się na stosie) są dostępne tylko z jednego wątku, który jest właścicielem tego stosu.
  2. drugim warunkiem jest to, że istnieje właściwość (często nazywana niezmienna ), która jest powiązana z tymi lokalizacjami pamięci dzielonej, która musi być prawdziwa lub ważna, aby program działał poprawnie. W powyższym przykładzie właściwość jest taka, że " totalRequests musi dokładnie reprezentować sumę liczba razy każdy wątek wykonał jakąkolwiek część instrukcji increment ". Zazwyczaj ta niezmienna właściwość musi mieć wartość true (w tym przypadku totalRequests musi mieć dokładną liczbę) przed aktualizacją, aby aktualizacja była poprawna.
  3. trzecim warunkiem jest to, że niezmienna właściwość nie utrzymuje się podczas jakiejś części aktualnej aktualizacji. (Jest przejściowo nieprawidłowy lub fałszywy podczas pewnej części przetwarzania). W tym konkretnym przypadku, od czasu całkowitego zapotrzebowania jest pobierane do czasu przechowywania zaktualizowanej wartości, totalRequests nie spełnia niezmiennika .
  4. czwarty i ostatni warunek, który musi wystąpić, aby wyścig się odbył (i aby kod nie jest to "bezpieczne dla wątku"), że inny wątek musi mieć dostęp do pamięci współdzielonej , podczas gdy niezmiennik jest uszkodzony, powodując niespójne lub nieprawidłowe zachowanie.
 42
Author: Charles Bretana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-05 14:55:06

Podoba mi się definicja z Brian Goetz współbieżności Java w praktyce za jej zrozumiałość

" klasa jest bezpieczna dla wątków, jeśli zachowuje się poprawnie, gdy jest dostępna z wielu wątków, niezależnie od planowania lub przeplatania wykonywania tych wątków przez środowisko runtime, i bez dodatkowej synchronizacji lub innej koordynacji ze strony kodu wywołującego."

 32
Author: Buu Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 14:32:11

Thread-safe-code działa tak, jak określono, nawet jeśli jest wprowadzany jednocześnie przez różne wątki. Często oznacza to, że wewnętrzne struktury danych lub operacje, które powinny działać nieprzerwanie, są chronione przed różnymi modyfikacjami w tym samym czasie.

 22
Author: Mnementh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-15 10:43:50

Jak zauważyli inni, bezpieczeństwo wątku oznacza, że fragment kodu będzie działał bez błędów, jeśli będzie używany przez więcej niż jeden wątek na raz.

Warto mieć świadomość, że czasami wiąże się to z kosztem czasu komputera i bardziej skomplikowanego kodowania, więc nie zawsze jest to pożądane. Jeśli klasa może być bezpiecznie używana tylko na jednym wątku, może być lepiej to zrobić.

Na przykład, Java ma dwie klasy, które są prawie równoważne, StringBuffer i StringBuilder. Różnica polega na tym, że StringBuffer jest thread-safe, więc pojedyncza instancja StringBuffer może być używana przez wiele wątków jednocześnie. StringBuilder nie jest bezpieczny dla wątku i jest zaprojektowany jako zamiennik o wyższej wydajności w tych przypadkach (zdecydowana większość), gdy ciąg jest zbudowany tylko przez jeden wątek.
 22
Author: Marcus Downing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-28 13:39:51

Łatwiej jest to zrozumieć, co sprawia, że kod nie jest bezpieczny dla wątków. Istnieją dwa główne problemy, które sprawią, że aplikacja wątkowa będzie miała niechciane zachowanie.

  • Dostęp do współdzielonej zmiennej bez blokowania
    Zmienna ta może być modyfikowana przez inny wątek podczas wykonywania funkcji. Chcesz temu zapobiec za pomocą mechanizmu blokującego, aby mieć pewność zachowania swojej funkcji. Ogólną zasadą jest utrzymywanie zamka przez jak najkrótszy czas możliwe.

  • Impas spowodowany wzajemną zależnością od współdzielonej zmiennej
    Jeśli masz dwie współdzielone zmienne A I B. w jednej funkcji, najpierw blokujesz A, a później blokujesz B. w innej funkcji, zaczynasz blokowanie B i po pewnym czasie blokujesz A. jest to potencjalna blokada, w której pierwsza funkcja będzie czekać na odblokowanie B, gdy druga funkcja będzie czekać na odblokowanie A. Ten problem prawdopodobnie nie wystąpi w Twoim środowisku programistycznym i tylko od czasu do czasu. Na unikaj tego, wszystkie zamki muszą być zawsze w tej samej kolejności.

 16
Author: Hapkido,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-15 07:42:09

Tak i nie.

Bezpieczeństwo wątków to coś więcej niż tylko upewnienie się, że udostępnione dane są dostępne tylko dla jednego wątku na raz. Musisz zapewnić sekwencyjny dostęp do udostępnionych danych, jednocześnie unikając warunków wyścigu, deadlocks, livelocks i resource .

Nieprzewidywalne wyniki podczas uruchamiania wielu wątków to nie wymagany warunek kodu bezpiecznego dla wątku, ale często jest to produkt uboczny. Na na przykład można skonfigurować schemat producent-konsument z kolejką współdzieloną, jednym wątkiem producenta i kilkoma wątkami konsumenckimi, a przepływ danych może być całkowicie przewidywalny. Jeśli zaczniesz wprowadzać więcej konsumentów, zobaczysz więcej losowych wyników.

 9
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 12:59:36

Zasadniczo wiele rzeczy może pójść nie tak w środowisku wielowątkowym (Zmiana kolejności instrukcji, częściowo skonstruowane obiekty, ta sama zmienna o różnych wartościach w różnych wątkach z powodu buforowania na poziomie CPU itp.).

Podoba mi się definicja podana przez współbieżność Javy w praktyce :

[część kodu] jest bezpieczna dla wątków, jeśli zachowuje się poprawnie, gdy jest dostępna z wielu wątków, niezależnie od harmonogramu lub przeplatania wykonania te wątki przez środowisko uruchomieniowe i bez dodatkowej synchronizacji lub innej koordynacji ze strony kodu wywołującego.

Przez poprawnie oznaczają one, że program zachowuje się zgodnie ze specyfikacją.

Zmyślony przykład

Wyobraź sobie, że wdrażasz licznik. Można powiedzieć, że zachowuje się poprawnie, jeśli:

  • counter.next() nigdy nie zwraca wartości, która została już zwrócona wcześniej (Zakładamy, że nie ma przepełnienia itd. dla prostoty)
  • wszystkie wartości od 0 do bieżącej wartości zostały zwrócone na pewnym etapie (żadna wartość nie jest pomijana)

Bezpieczny licznik wątków zachowywałby się zgodnie z tymi regułami niezależnie od tego, ile wątków uzyskuje do niego dostęp jednocześnie (co zazwyczaj nie miałoby miejsca w przypadku naiwnej implementacji).

Uwaga: cross-post na programistów

 8
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-12 07:31:21

Simply-code będzie działać poprawnie, jeśli wiele wątków wykonuje ten kod w tym samym czasie.

 7
Author: Greg Balajewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-12 09:27:12

Nie myl bezpieczeństwa wątku z determinizmem. Kod bezpieczny dla wątku może być również niedeterministyczny. Biorąc pod uwagę trudność debugowania problemów z kodem gwintowanym, jest to prawdopodobnie normalny przypadek. :-)

Thread safety po prostu zapewnia, że gdy wątek modyfikuje lub czyta udostępnione dane, żaden inny wątek nie może uzyskać do niego dostępu w sposób, który zmienia dane. Jeśli twój kod zależy od określonego zlecenia wykonania dla poprawności, to potrzebujesz innych mechanizmów synchronizacji poza tymi wymagane dla bezpieczeństwa wątku, aby to zapewnić.

 3
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 12:31:51

Aby uzupełnić inne odpowiedzi:

Synchronizacja jest tylko zmartwieniem, gdy kod w Twojej metodzie robi jedną z dwóch rzeczy:

  1. działa z jakimś zewnętrznym zasobem, który nie jest bezpieczny dla wątku.
  2. odczytuje lub zmienia trwałe pole obiektu lub Klasy

Oznacza to, że zmienne zdefiniowane w Twojej metodzie są zawsze threadsafe. Każde wywołanie metody ma własną wersję tych zmiennych. Jeśli metoda jest wywoływana przez inny wątek, lub przez ten sam wątek, lub nawet jeśli metoda sama się wywoła (rekurencja), wartości tych zmiennych nie są współdzielone.

Planowanie wątków nie jest gwarantowane round-robin. Zadanie może całkowicie zablokować procesor kosztem wątków o tym samym priorytecie. Możesz użyć wątku.yield (), aby mieć sumienie. Możesz użyć (w Javie) wątku.setPriority (Gwint.NORM_PRIORITY-1) aby obniżyć priorytet wątku

Plus uwaga na:

  • duży koszt czasu pracy (już wspominany przez innych) w aplikacjach, które działają na tych" bezpiecznych dla wątków " strukturach.
  • wątek.sen (5000) ma spać przez 5 sekund. Jeśli jednak ktoś zmieni czas systemowy, możesz spać bardzo długo lub wcale. System operacyjny rejestruje czas budzenia w formie absolutnej, a nie względnej.
 3
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 12:41:38

Chciałbym dodać więcej informacji na temat innych dobrych odpowiedzi.

bezpieczeństwo wątku oznacza, że wiele wątków może zapisywać/odczytywać dane w tym samym obiekcie bez błędów niespójności pamięci. W programie wielowątkowym program bezpieczny dla wątków nie powoduje skutków ubocznych współdzielonych danych.

[[16]} spójrz na to pytanie SE, aby uzyskać więcej szczegółów:

Co oznacza threadsafe?

Gwarancja programu Thread safe spójność pamięci.

Ze strony dokumentacji oracle na zaawansowanym współbieżnym API:

Właściwości Spójności Pamięci:

Rozdział 17 specyfikacji języka Java ™ definiuje relację happens-before dotyczącą operacji pamięci, takich jak odczyt i zapis współdzielonych zmiennych. wyniki zapisu w jednym wątku są gwarantowane, że będą widoczne dla odczytu w innym wątku tylko wtedy, gdy operacja zapisu nastąpi-przed odczytem operacja .

Konstrukcje synchronized i volatile, a także metody Thread.start() i Thread.join(), mogą tworzyć happens-before relacje.

Metody wszystkich klas w java.util.concurrent i jej podpakietach rozszerzają te gwarancje do synchronizacji wyższego poziomu. w szczególności:

  1. akcje w wątku przed umieszczeniem obiektu w dowolnej współbieżnej kolekcji zdarzają się-przed akcjami po uzyskaniu dostępu lub usunięciu tego elementu z kolekcja w innym wątku.
  2. działania w wątku przed złożeniem Runnable do Executor zdarzają się-przed rozpoczęciem jego wykonania. Podobnie w przypadku połączeń złożonych do ExecutorService.
  3. działania podejmowane przez obliczenia asynchroniczne reprezentowane przez Future akcje happen-before po pobraniu wyniku przez Future.get() w innym wątku.
  4. akcje przed "zwolnieniem" synchronizer metody takie jak Lock.unlock, Semaphore.release, and CountDownLatch.countDown happen-before akcje po udana metoda "pozyskania", taka jak Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await na tym samym obiekcie synchronizatora w innym wątku.
  5. dla każdej pary wątków, które pomyślnie wymieniają obiekty za pomocą Exchanger, akcje poprzedzające exchange() w każdym wątku zdarzają się-przed tymi, które następują po odpowiedniej Exchange() w innym wątku.
  6. działania przed wywołaniem CyclicBarrier.await i Phaser.awaitAdvance (a także jego warianty) zdarzają się-przed działaniami wykonywanymi przez działanie bariery i działaniami wykonywanymi przez działanie bariery happen-czynności poprzedzające pomyślny powrót z odpowiedniego oczekują w innych wątkach.
 3
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32

Tak i tak. Oznacza to, że dane nie są modyfikowane przez więcej niż jeden wątek jednocześnie. Jednak twój program może działać zgodnie z oczekiwaniami i wydawać się bezpieczny dla wątków, nawet jeśli zasadniczo tak nie jest.

Zauważ, że nieprzewidywalność wyników jest konsekwencją "warunków wyścigu", które prawdopodobnie skutkują modyfikacją danych w innej kolejności niż oczekiwana.

 1
Author: Steve Knight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 12:36:15

W najprostszych słowach: P Jeśli bezpieczne jest wykonywanie wielu wątków na bloku kodu, jest to thread safe *

*obowiązują warunki

Warunki są wymienione przez inne odpowiedzi, takie jak 1. Wynik powinien być taki sam, jeśli wykonasz jeden wątek lub wiele wątków nad nim itp.

 0
Author: shabby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-15 09:19:52