"스레드 안전"이라는 용어의 의미는 무엇입니까?


367

두 개의 스레드가 기본 데이터를 동시에 변경할 수 없다는 것을 의미합니까? 아니면 여러 스레드가 해당 코드 세그먼트를 실행할 때 주어진 코드 세그먼트가 예측 가능한 결과로 실행된다는 것을 의미합니까?


8
이 문제에 관해 흥미로운 토론을 보았습니다 : blogs.msdn.com/ericlippert/archive/2009/10/19/…
Sebastian

답변:


256

Wikipedia에서 :

스레드 안전성은 멀티 스레드 프로그램의 맥락에서 적용 가능한 컴퓨터 프로그래밍 개념입니다. 여러 스레드가 동시에 실행하는 동안 올바르게 작동하면 코드 조각이 스레드로부터 안전합니다. 특히, 여러 공유 스레드가 동일한 공유 데이터에 액세스 할 필요성과 주어진 시간에 하나의 스레드 만 공유 데이터 조각에 액세스 할 필요성을 충족시켜야합니다.

스레드 안전을 달성하는 몇 가지 방법이 있습니다.

재입국 :

한 작업에서 부분적으로 실행하고 다른 작업에서 다시 입력 한 다음 원래 작업에서 다시 시작할 수 있도록 코드를 작성합니다. 이를 위해서는 정적 또는 전역 변수 대신 각 작업의 로컬 변수, 일반적으로 스택에 상태 정보를 저장해야합니다.

상호 배제 :

공유 데이터에 대한 액세스는 언제든지 하나의 스레드 만 공유 데이터를 읽거나 쓰도록하는 메커니즘을 사용하여 직렬화됩니다. 코드 조각이 여러 공유 데이터 조각에 액세스하는 경우 세심한주의가 필요합니다. 문제에는 경쟁 조건, 교착 상태, 라이브 록, 기아 및 여러 운영 체제 교과서에 열거 된 다양한 기타 문제가 포함됩니다.

스레드 로컬 스토리지 :

변수는 지역화되어 각 스레드마다 고유 한 개인 사본이 있습니다. 이러한 변수는 서브 루틴 및 기타 코드 경계에 걸쳐 값을 유지하며, 액세스하는 코드가 재진입 될 수 있더라도 각 스레드에 대해 로컬이므로 스레드 안전합니다.

원자력 운영 :

다른 스레드에 의해 중단 될 수없는 원자 연산을 사용하여 공유 데이터에 액세스합니다. 일반적으로 런타임 라이브러리에서 사용 가능한 특수 기계 언어 명령어를 사용해야합니다. 작업이 원자 적이기 때문에 공유 데이터는 다른 스레드가 액세스하는 내용에 관계없이 항상 유효한 상태로 유지됩니다. 원자 연산은 많은 스레드 잠금 메커니즘의 기초를 형성합니다.

더 읽기 :

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



4
이 링크는 기술적으로 몇 가지 중요한 사항이 없습니다. 해당 공유 메모리는 변경 가능해야하며 (읽기 전용 메모리는 스레드 안전하지 않을 수 없음) 여러 스레드는 a) 메모리가 일치하지 않는 중간에 메모리에서 여러 번 쓰기 작업을 수행해야합니다 (잘못된). 상태, 그리고 b) 메모리가 일관성이없는 동안 다른 스레드가 해당 스레드를 중단 할 수 있도록합니다.
Charles Bretana

20
검색했을 때 Google의 첫 번째 결과는 Wiki이므로 여기서 중복되지는 않습니다.
Ranvir

"함수에 액세스하는 코드"는 무엇을 의미합니까? 실행되는 함수 자체는 코드입니다.
Koray Tugay 2016 년

82

스레드 안전 코드는 많은 스레드가 동시에 실행하더라도 작동하는 코드입니다.

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


34
같은 과정에서!
Ali Afshar

실제로, 같은 과정에서 :)
Marek Blotny

4
"몇 주 동안 안정적으로 실행될 코드를 작성하려면 극도로 편집증이 필요합니다." 그건 내가 좋아하는 인용문입니다 :)
Jim T

5
어이! 이 답변은 질문을 다시 시작합니다! --- 그리고 왜 같은 프로세스 내에서만 ?? 여러 스레드가 다른 프로세스에서 코드를 실행할 때 코드가 실패하면 "공유 메모리"가 디스크 파일에있을 수 있습니다. 스레드 안전하지 않습니다 !!
Charles Bretana

1
@ mg30rg. 아마도 혼동은 코드 블록이 여러 프로세스에 의해 실행될 때 프로세스 당 하나의 스레드에서만 실행될 때 다중 스레드 시나리오가 아닌 "단일 스레드"시나리오라고 생각한 결과 일 것입니다. . 이 아이디어는 잘못이 아닙니다. 그것은 단지 잘못된 정의입니다. 분명히 여러 프로세스가 동기화 된 방식으로 동일한 스레드에서 일반적으로 실행되지는 않습니다 (설계에 따라 프로세스가 서로 조정되고 OS가 프로세스간에 스레드를 공유하는 드문 경우는 제외)
Charles Bretana

50

더 유익한 질문은 코드가 스레드에 안전하지 않게 만드는 것입니다. 그리고 정답은 4 가지 조건이 있어야한다는 것입니다 ... 다음 코드를 상상해보십시오 (그리고 기계 언어 번역).

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. 첫 번째 조건은 둘 이상의 스레드에서 액세스 할 수있는 메모리 위치가 있다는 것입니다. 일반적으로 이러한 위치는 전역 / 정적 변수이거나 전역 / 정적 변수에서 도달 할 수있는 힙 메모리입니다. 각 스레드는 함수 / 메소드 범위의 지역 변수에 대한 자체 스택 프레임을 가져 오므로 스택에있는 이러한 로컬 함수 / 메소드 변수 otoh는 해당 스택을 소유 한 하나의 스레드에서만 액세스 할 수 있습니다.
  2. 두 번째 조건은 이러한 공유 메모리 위치와 연관된 특성 (종종 불변 이라고 함 )이 있으며 프로그램이 올바르게 작동하기 위해서는 true 또는 유효해야한다는 것입니다. 위의 예에서 속성은 " totalRequests는 스레드가 증가 문의 일부를 실행 한 총 횟수를 정확하게 나타내야합니다 ". 일반적으로 업데이트가 올바르게 수행 되려면 업데이트가 발생하기 전에이 변하지 않는 특성이 true (이 경우 totalRequests가 정확한 수를 보유해야 함)를 보유해야합니다.
  3. 세 번째 조건은 실제 업데이트의 일부 부분에서 고정 속성이 유지되지 않는 것입니다. (일부 처리 중에 일시적으로 유효하지 않거나 거짓입니다). 이 특정 경우, totalRequests가 페치 된 시간부터 갱신 된 값이 저장 될 때까지 totalRequests는 불변을 만족 시키지 않습니다 .
  4. 레이스가 발생하고 코드 가 "스레드 안전"상태가 되지 않기 위해 발생해야하는 네 번째이자 마지막 조건 은 불변이 깨지는 동안 다른 스레드가 공유 메모리에 액세스 할 수 있어야 하므로 불일치 또는 잘못된 행동.

6
여기에는 데이터 레이스 라고 알려진 것만 포함되며 물론 중요합니다. 그러나 코드가 스레드로부터 안전하지 않은 다른 방법 (예 : 교착 상태로 이어질 수있는 잘못된 잠금)이 있습니다. Java 스레드 어딘가에서 System.exit ()를 호출하는 것과 같은 간단한조차도 해당 코드는 스레드 안전하지 않습니다.
Ingo

2
나는 이것이 어느 정도 의미 론적이라고 생각하지만 교착 상태를 일으킬 수있는 잘못된 잠금 코드는 코드를 안전하지 않게 만든다고 주장합니다. 첫째, 위에서 설명한 경쟁 조건이 가능하지 않으면 코드를 먼저 잠글 필요가 없습니다. 그런 다음 교착 상태를 유발하는 방식으로 잠금 코드를 작성하면 스레드 안전하지 않으며 잘못된 코드입니다.
Charles Bretana 2016

1
그러나 단일 스레드를 실행할 때는 교착 상태가 발생하지 않으므로 대부분의 경우 "스레드 안전"이라는 직관적 의미에 속하게됩니다.
Jon Coombs

물론 멀티 스레드를 실행하지 않으면 교착 상태가 발생할 수 없지만 한 컴퓨터에서 실행 중이면 네트워크 문제가 발생할 수 없다는 것과 같습니다. 프로그래머가 코드를 작성하여 업데이트를 완료하기 전에 중요한 코드 행을 벗어나 다른 서브 루틴의 변수를 수정하면 다른 스레드도 단일 스레드로 발생할 수 있습니다.
Charles Bretana

34

나는 Brian Goetz의 Java Concurrency의 정의가 포괄적이라는 점을 좋아합니다.

"클래스는 런타임 환경에 의한 스레드 실행의 스케줄링 또는 인터리빙에 관계없이 호출 스레드의 일부에 대한 추가 동기화 또는 기타 조정없이 여러 스레드에서 액세스 될 때 올바르게 작동하는 경우 스레드로부터 안전합니다. "


이 정의는 불완전하고 구체적이지 않으며 포괄적이지 않습니다. 한 번만 몇 번이나 안전하게 실행해야합니까? 열 번? 매번? 시간의 80 %? "안전하지 않은"항목을 지정하지 않습니다. 안전하게 실행하지 못하지만 0으로 나누기 오류가 발생하여 실패한 경우 스레드가 "안전하지 않은"것입니까?
Charles Bretana 2016 년

다음에 더 시민이되고 토론 할 수 있습니다. 이것은 레딧이 아니며 무례한 사람들과 이야기하는 기분이 아닙니다.
Buu Nguyen

자신에 대한 모욕으로 다른 사람의 정의에 대한 해석 의견이 말하고 있습니다. 감정적으로 반응하기 전에 물질을 읽고 이해해야합니다. 내 의견에 대해 사소한 것은 없습니다. 나는 정의의 의미에 대해 지적하고 있었다. 요점을 설명하기 위해 사용한 예가 불편한 경우 죄송합니다.
Charles Bretana 2016 년

28

다른 사람들이 지적했듯이 스레드 안전은 한 번에 두 개 이상의 스레드가 사용하는 경우 코드가 오류없이 작동한다는 것을 의미합니다.

때때로 컴퓨터 비용과 복잡한 코딩 비용이 발생하기 때문에 항상 바람직하지는 않습니다. 하나의 스레드에서만 클래스를 안전하게 사용할 수 있다면 그렇게하는 것이 좋습니다.

예를 들어, 자바는 거의 동등한 두 개의 클래스를 가지고 StringBufferStringBuilder. 차이점은 StringBuffer스레드로부터 안전하므로 StringBuffer한 번에 여러 스레드에서 단일 인스턴스를 사용할 수 있다는 것입니다. StringBuilder스레드로부터 안전하지 않으며 String이 하나의 스레드만으로 빌드 될 때 이러한 경우 (대부분의 경우)를위한 고성능 대체물로 설계되었습니다.


22

스레드 안전 코드는 다른 스레드가 동시에 입력하더라도 지정된대로 작동합니다. 이는 종종 중단없이 실행해야하는 내부 데이터 구조 또는 작업이 동시에 다른 수정으로부터 보호됨을 의미합니다.


21

이해하기 쉬운 방법은 코드를 스레드로부터 안전하지 않게 만드는 것입니다. 스레드 응용 프로그램이 원치 않는 동작을하게하는 두 가지 주요 문제가 있습니다.

  • 잠금없이 공유 변수에 액세스이 변수
    는 기능을 실행하는 동안 다른 스레드에서 수정할 수 있습니다. 기능의 동작을 확인하기 위해 잠금 메커니즘으로이를 방지하려고합니다. 일반적으로 가장 짧은 시간 동안 잠금을 유지하는 것이 좋습니다.

  • 공유 변수에 대한 상호 종속성으로 인한 교착 상태
    두 개의 공유 변수 A와 B가있는 경우 한 함수에서 A를 먼저 잠근 다음 나중에 B를 잠급니다. 다른 함수에서는 B를 잠그고 잠시 후 A를 잠급니다. 는 두 번째 기능이 A 잠금 해제를 기다릴 때 첫 번째 기능이 B 잠금 해제를 기다릴 수있는 잠재적 교착 상태입니다. 이 문제는 개발 환경에서 발생하지 않으며 때때로 만 발생합니다. 이를 방지하려면 모든 잠금 장치는 항상 같은 순서로되어 있어야합니다.


9

예, 아니오

스레드 안전성은 한 번에 하나의 스레드 만 공유 데이터에 액세스 할 수 있도록하는 것보다 조금 더 중요합니다. 경쟁 조건 , 교착 상태 , 라이브 록리소스 부족을 피하면서 동시에 공유 데이터에 순차적으로 액세스해야 합니다.

여러 스레드가 실행되고 예측할 수없는 결과입니다 하지 스레드 안전 코드의 필요 조건이지만 종종 부산물이다. 예를 들어, 공유 큐, 하나의 생산자 스레드 및 소수의 소비자 스레드 로 생산자-소비자 구성표를 설정할 수 있으며 데이터 흐름을 완벽하게 예측할 수 있습니다. 더 많은 소비자를 소개하기 시작하면 더 무작위로 보이는 결과가 나타납니다.


9

본질적으로, 다중 스레드 환경에서 많은 것들이 잘못 될 수 있습니다 (명령 순서 변경, 부분적으로 생성 된 객체, CPU 수준에서의 캐싱으로 인해 다른 스레드에서 다른 값을 갖는 동일한 변수 등).

실제로 Java Concurrency에서 제공 한 정의가 마음 에 듭니다 .

[일부 코드]는 런타임 환경에서 해당 스레드의 실행을 예약 또는 인터리빙하고 여러 스레드에서 액세스 할 때 올바르게 동작하는 경우 스레드로부터 안전합니다. 호출 코드.

하여 제대로 그들은 그것의 사양을 준수하는 프로그램 동작합니다을 의미한다.

고안된 예

카운터를 구현한다고 상상해보십시오. 다음과 같은 경우 올바르게 작동한다고 말할 수 있습니다.

  • counter.next() 이전에 이미 반환 된 값을 반환하지 않습니다 (간단 성을 위해 오버플로 등이 없다고 가정 함)
  • 0에서 현재 값까지의 모든 값이 특정 단계에서 리턴되었습니다 (값을 건너 뛰지 않음)

스레드 안전 카운터는 동시에 액세스하는 스레드 수에 관계없이 이러한 규칙에 따라 작동합니다 (일반적으로 순진한 구현에는 해당되지 않음).

참고 : 프로그래머의 교차 게시물



5

스레드 안전성을 결정론과 혼동하지 마십시오. 스레드 안전 코드는 비 결정적 일 수도 있습니다. 스레드 코드로 문제를 디버깅하는 데 어려움이 있다면 이것은 아마도 정상적인 경우 일 것입니다. :-)

스레드 안전성은 단순히 스레드가 공유 데이터를 수정하거나 읽을 때 다른 스레드가 데이터를 변경하는 방식으로 액세스 할 수 없도록합니다. 코드가 정확한 실행 순서에 의존하는 경우이를 보장하기 위해 스레드 안전에 필요한 것 이외의 다른 동기화 메커니즘이 필요합니다.


5

다른 좋은 답변 위에 더 많은 정보를 추가하고 싶습니다.

스레드 안전성은 여러 스레드가 메모리 불일치 오류없이 동일한 객체에서 데이터를 쓰거나 읽을 수 있음을 의미합니다. 다중 스레드 프로그램에서 스레드 안전 프로그램은 공유 데이터에 부작용을 일으키지 않습니다 .

자세한 내용은이 SE 질문을 살펴보십시오.

스레드 세이프 란 무엇입니까?

스레드 안전 프로그램은 메모리 일관성을 보장합니다 .

고급 동시 API의 Oracle 문서 페이지 에서 :

메모리 일관성 속성 :

Java ™ 언어 스펙의 17 장은 공유 변수의 읽기 및 쓰기와 같은 메모리 조작에서 발생하는 관계를 정의합니다. 하나의 스레드에 의한 쓰기 결과는 읽기 작업 이전에 쓰기 작업이 발생하는 경우에만 다른 스레드가 읽을 수 있도록 보장됩니다 .

synchronizedvolatile구조뿐만 아니라,로 Thread.start()Thread.join()방법, 캔 형상이 발생하기 전에- 관계.

모든 클래스 java.util.concurrent와 그 하위 패키지 의 메소드는 이러한 보증을 더 높은 수준의 동기화 로 확장 합니다. 특히:

  1. 객체를 동시 수집에 배치하기 전에 스레드에서 수행하는 작업은 다른 스레드의 컬렉션에서 해당 요소를 액세스하거나 제거한 후에 수행됩니다.
  2. 실행이 시작되기 전에 a Runnable에 제출하기 전에 스레드의 조치 Executor. 마찬가지로가 제출 된 Callable에 대해서도 마찬가지입니다 ExecutorService.
  3. 비동기 계산에 의해 취해진 조치 는 다른 스레드 Future를 통해 결과를 검색 한 후 발생 하는 조치로 표시됩니다 Future.get().
  4. 다른 스레드의 동일한 동기화 기 객체에서 와 같이 성공적인 "획득"방법에 후속하는 사전 조치 와 같은 동기화 기 메소드 를 "릴리스" Lock.unlock, Semaphore.release, and CountDownLatch.countDown하기 전의 조치 Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await.
  5. 를 통해 객체를 성공적으로 교환하는 각 스레드 쌍 에 대해 각 스레드의 Exchanger이전 작업 exchange()은 다른 스레드의 해당 exchange () 이후의 작업보다 먼저 발생합니다.
  6. 호출하기 전의 조치 ( CyclicBarrier.awaitPhaser.awaitAdvance그 변형)는 배리어 조치에 의해 수행 된 조치 이전에 발생하고 배리어 조치에 의해 수행 된 조치는 해당 스레드에서 성공적으로 리턴 된 조치 후에 다른 스레드에서 대기합니다.

4

다른 답변을 완료하려면

메소드의 코드가 다음 두 가지 중 하나를 수행 할 때만 동기화가 걱정됩니다.

  1. 스레드 안전하지 않은 외부 리소스와 함께 작동합니다.
  2. 영구 객체 또는 클래스 필드를 읽거나 변경

즉, 메소드 내에 정의 된 변수는 항상 스레드 안전합니다. 메소드에 대한 모든 호출에는 이러한 변수의 자체 버전이 있습니다. 메소드가 다른 스레드 또는 동일한 스레드에 의해 호출되거나 메소드가 자체 호출 (재귀)하는 경우에도 이러한 변수의 값은 공유되지 않습니다.

스레드 스케줄링은 라운드 로빈 일 수 없습니다 . 작업은 동일한 우선 순위의 스레드를 희생하여 CPU를 완전히 비울 수 있습니다. Thread.yield ()를 사용하여 양심을 가질 수 있습니다. (Java에서) Thread.setPriority (Thread.NORM_PRIORITY-1)를 사용하여 스레드의 우선 순위를 낮출 수 있습니다

또한 다음을주의하십시오 :

  • 이러한 "스레드 안전"구조를 반복하는 응용 프로그램에 대한 많은 런타임 비용 (이미 언급 됨).
  • Thread.sleep (5000)은 5 초 동안 휴면 상태입니다. 그러나 누군가가 시스템 시간을 변경하면 아주 오랫동안 잠을 자거나 전혀 시간을 보내지 않을 수 있습니다. OS는 웨이크 업 시간을 상대 형식이 아닌 절대 형식으로 기록합니다.

2

그렇습니다. 데이터가 둘 이상의 스레드에 의해 동시에 수정되지 않음을 의미합니다. 그러나 프로그램이 예상대로 작동하고 기본적으로 안전하지 않더라도 스레드로부터 안전 해 보일 수 있습니다.

결과의 예측 불가능 성은 데이터가 예상 된 순서 이외의 순서로 수정 될 수있는 '인종 조건'의 결과입니다.


2

예를 들어 이것에 대답하자 :

class NonThreadSafe {

    private int counter = 0;

    public boolean countTo10() {
        count = count + 1;
        return (count == 10);
    }

countTo10메서드는 카운터에 하나를 추가 한 다음 카운트가 10에 도달하면 true를 반환합니다. 한 번만 true를 반환해야합니다.

하나의 스레드 만 코드를 실행하는 한 작동합니다. 두 개의 스레드가 동시에 코드를 실행하면 다양한 문제가 발생할 수 있습니다.

예를 들어, count가 9로 시작하면 한 스레드가 1을 계산하여 계산 (10 만들기) 할 수 있지만 두 번째 스레드가 메소드를 입력하고 1을 다시 추가하여 (11 만들기) 첫 번째 스레드가 10과의 비교를 실행할 수 있습니다. 그런 다음 두 스레드가 비교를 수행하고 count가 11이고 true를 반환하지 않는다는 것을 알게됩니다.

따라서이 코드는 스레드로부터 안전하지 않습니다.

본질적으로 모든 멀티 스레딩 문제는 이러한 종류의 문제의 변형으로 인해 발생합니다.

해결책은 추가 및 비교를 분리 할 수 ​​없도록하는 것입니다 (예를 들어 두 종류의 동기화 코드로 두 명령문을 묶음). 이러한 코드는 스레드로부터 안전합니다.


1

적어도 C ++에서는 스레드 안전 이 이름에서 많이 벗어나는 점에서 약간 잘못된 것으로 생각합니다. 스레드 안전을 위해 코드는 일반적으로 사전 예방 적 이어야 합니다. 일반적으로 수동적 인 품질이 아닙니다.

클래스가 밟지 않도록하려면 오버 헤드를 추가하는 "추가"기능이 있어야합니다. 이러한 기능은 클래스 구현의 일부이며 일반적으로 인터페이스에 숨겨져 있습니다. 즉, 다른 스레드는 다른 스레드에 의한 동시 액세스와의 충돌에 대해 걱정할 필요없이 클래스 멤버에 액세스 할 수 있으며 평범한 오래된 일반 휴먼 코딩 스타일을 사용하여 매우 게으른 방식으로 그렇게 할 수 있습니다. 이미 호출 된 코드의 내장으로 롤링 된 모든 미친 동기화 작업.

이것이 일부 사람들이 내부적으로 동기화 된 용어를 선호하는 이유 입니다.

용어집

내가 만난 이러한 아이디어에 대한 세 가지 주요 용어 세트가 있습니다. 첫 번째이자 역사적으로 더 대중적이지만 더 나쁘다.

  1. 스레드 안전
  2. 스레드 안전 하지 않음

두 번째 (그리고 더 나은)는 다음과 같습니다.

  1. 실 증명
  2. 스레드 호환
  3. 적대적 실

세번째는 :

  1. 내부적으로 동기화
  2. 외부 동기화
  3. 동기화 불가능

유추

스레드 안전 ~ 스레드 증명 ~ 내부 동기화

의 예 내부적으로 동기화 (일명. 스레드 안전 또는 스레드 증거 ) 시스템 호스트가 문을 열고 인사를 할 수없는 식당이 있습니다. 호스트는 여러 고객을 처리하기위한 레스토랑 메커니즘의 일부이며, 파티 규모를 고려하거나 대기 시간을 고려하는 등 대기중인 고객의 좌석을 최적화하기 위해 다소 까다로운 트릭을 사용할 수 있습니다. 전화로 예약 할 수도 있습니다. 식당은 내부적으로 동기화되어 있으며이 모든 것이 식당과 상호 작용하기위한 인터페이스의 일부이기 때문입니다.

스레드 안전 하지는 않지만 (좋은) ~ 스레드 호환 ~ 외부 동기화 ~ 무료 스레드

은행에 간다고 가정하십시오. 은행원에 대한 경쟁, 즉 경쟁이 있습니다. 당신은 야만인이 아니기 때문에, 자원에 대한 논쟁 중에 행하는 가장 좋은 일은 문명화 된 존재처럼 대기하는 것입니다. 아무도 기술적으로 당신을 그렇게하지 않습니다. 우리는 당신이 스스로 그것을하기 위해 필요한 소셜 프로그래밍이 있기를 바랍니다. 이런 의미에서 은행 로비는 외부 적으로 동기화됩니다. 스레드 안전하지 않다고 말해야합니까? 이것이 thread-safe , thread-unsafe 양극성 용어 집합을 사용하는 경우의 의미입니다 . 아주 좋은 용어는 아닙니다. 더 나은 용어는 외부 적으로 동기화됩니다.은행 로비는 여러 고객이 액세스하는 데 적대적이지 않지만 동기화하는 작업은 수행하지 않습니다. 고객은 스스로 그렇게합니다.

"free threaded"라고도합니다. 여기서 "free"는 "lice from free"또는이 경우에는 lock과 같습니다. 보다 정확하게는 동기화 기본 요소입니다. 그렇다고 코드가 프리미티브없이 여러 스레드에서 실행될 수 있다는 의미는 아닙니다. 그것은 이미 설치되어 있지 않은 것을 의미하며 코드 사용자는 자신에게 적합하지만 직접 설치하는 것은 귀하에게 달려 있습니다. 자체 동기화 프리미티브를 설치하는 것은 어려울 수 있으며 코드에 대해 열심히 생각해야하지만 오늘날의 하이퍼 스레드 CPU에서 프로그램이 실행되는 방식을 사용자 정의 할 수있게함으로써 가능한 가장 빠른 프로그램으로 이어질 수 있습니다.

스레드 안전하지 않음 (및 불량) ~ 스레드 적대적 ~ 동기화 불가능

실 적대적 시스템 의 일상 비유의 예 는 스포츠카가 깜박임을 사용하는 것을 거부하고 레인을 바꾸는 것입니다. 그들의 운전 스타일은 당신이 그들과 조화를 이룰 수 없기 때문에 적대적 이거나 비 동기화 될 수 있습니다. 이것을 방지하십시오. 이 패턴은 반 사회적 으로 더 광범위하게 생각할 수 있는데 , 이는 스레드에 덜 구체적이고 많은 프로그래밍 영역에 더 일반적으로 적용되기 때문에 선호합니다.

thread safe et al. 용어가 잘못되었습니다

첫 번째 및 가장 오래된 용어 집합은 스레드의 적개심스레드 호환성을 더 잘 구분하지 못합니다 . 스레드 호환성은 소위 스레드 안전성보다 수동적이지만 호출 된 코드가 동시 스레드 사용에 안전하지 않다는 것을 의미하지는 않습니다. 이는 내부 구현의 일부로 제공하는 대신이를 허용하여 호출 코드에 적용 할 수있는 동기화에 대해 수동적임을 의미합니다. 스레드 호환 은 대부분의 경우 기본적으로 코드를 작성하는 방법이지만, 이는 기본적 으로 안티 안전 인 것처럼 스레드 안전하지 않은 것으로 잘못 인식되는 경우가 많습니다 . 이는 프로그래머에게 혼란을 일으키는 주요 지점입니다.

참고 : 많은 소프트웨어 설명서는 실제로 "스레드 안전"이라는 용어를 사용하여 "스레드 호환"을 지칭하며 이미 혼란스러워하는 것에 더 많은 혼란을줍니다! 이 이유로 인해 "스레드 안전"및 "스레드 안전하지 않은"이라는 용어를 사용하는 것은 피할 수 없습니다. 일부 소스는 "스레드 안전"이라고 부르는 반면 다른 소스는 동의 할 수 없기 때문에 "스레드 안전하지 않은"이라고 부릅니다. 안전에 대한 몇 가지 추가 표준 (동기화 프리미티브)을 충족해야하는지 또는 "안전한"것으로 간주되기 위해 적대적이지 않아야합니다. 따라서 다른 엔지니어와의 위험한 오해를 피하기 위해 이러한 용어를 사용하지 말고 더 똑똑한 용어를 사용하십시오.

우리의 목표 알림

본질적으로, 우리의 목표는 혼돈을 파괴하는 것입니다.

우리는 신뢰할 수있는 결정 론적 시스템을 만들어서 그렇게합니다. 결정 성은 비용이 많이 들며, 대부분 병렬 처리, 파이프 라이닝 및 재정렬에 대한 기회 비용 때문에 발생합니다. 우리는 비용을 낮게 유지하는 데 필요한 결정론의 양을 최소화하려고 노력할뿐만 아니라, 어떤 결정론을 감당할 수 있는지 결정하는 것을 피할 수 있습니다.

스레드 동기화는 순서를 늘리고 혼돈을 줄이는 것입니다. 이를 수행하는 수준은 위에서 언급 한 용어에 해당합니다. 최고 수준은 시스템이 항상 완전히 예측 가능한 방식으로 작동 함을 의미합니다. 두 번째 수준은 호출 코드가 예측할 수없는 가능성을 확실하게 감지 할 수있을 정도로 시스템이 충분히 작동 함을 의미합니다. 예를 들어, 조건 변수 의 가짜 웨이크 업 또는 준비되지 않았기 때문에 뮤텍스를 잠그지 못한 경우. 세 번째 수준은 시스템이 다른 사람과 게임을하기에 충분하지 않으며 혼돈없이 단일 스레드 만 실행할 수 있다는 의미입니다.


1

대신 생각의 코드 또는 클래스 스레드 안전이나하지, 나는 생각하는 것이 더 도움이된다 생각 행동 thread 세이프되고있다. 임의의 스레딩 컨텍스트에서 실행될 때 지정된대로 동작 할 경우 두 가지 조치는 스레드 안전입니다. 대부분의 경우 클래스는 스레드 안전 방식으로 일부 작업 조합을 지원하고 그렇지 않은 작업을 지원합니다.

예를 들어, 배열 목록 및 해시 세트와 같은 많은 컬렉션은 처음에 하나의 스레드로만 액세스하고 참조가 다른 스레드에 표시 된 후에는 절대 수정되지 않으면 임의의 조합으로 임의의 방식으로 읽을 수 있음을 보장합니다 방해없는 실의.

더 흥미롭게도 .NET의 원래 비 제네릭 컬렉션과 같은 일부 해시 세트 컬렉션은 항목이 제거되지 않는 한 하나의 스레드 만 쓰려고 시도하는 경우 모든 스레드를 컬렉션을 읽는 것은 업데이트가 지연되고 임의의 순서로 발생할 수 있지만 컬렉션이 정상적으로 작동하는 컬렉션에 액세스하는 것처럼 동작합니다. 스레드 # 1이 X를 추가 한 다음 Y를 추가하고 스레드 # 2가 Y를 찾은 다음 X를 보는 경우 스레드 # 2가 Y가 존재하지만 X는 존재하지 않는 것을 볼 수 있습니다. 이러한 동작이 "스레드 안전"인지 여부는 스레드 # 2가 해당 가능성을 처리 할 준비가되었는지 여부에 따라 결정됩니다.

마지막으로, 특히 통신 라이브러리를 차단하는 일부 클래스에는 다른 모든 메소드와 관련하여 스레드로부터 안전한 "클로즈"또는 "폐기"메소드가있을 수 있지만, 스레드에서 안전한 다른 메소드는 없습니다. 서로. 스레드가 블로킹 읽기 요청을 수행하고 프로그램 사용자가 "취소"를 클릭하면 읽기를 수행하려는 스레드가 닫기 요청을 발행 할 방법이 없습니다. 그러나, 닫기 / 삭제 요청은 가능한 빨리 읽기 요청이 취소되도록하는 플래그를 비동기 적으로 설정할 수 있습니다. 스레드에서 닫기가 수행되면 객체가 쓸모 없게되고 향후 작업에 대한 모든 시도가 즉시 실패합니다.


0

가장 간단한 단어 : P 코드 블록에서 여러 스레드를 실행하는 것이 안전하면 스레드 안전합니다. *

* 조건이 적용됩니다

조건은 1과 같은 다른 답변에 의해 언급됩니다. 결과는 하나 이상의 스레드를 실행하거나 그 이상의 스레드를 실행하는 경우와 동일해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.