• 원자적 연산 (atomic operation)

    Untitled

    • 단일해서 더 이상 잘게 쪼갤 수 없는 연산(operation)

    • 어떤 연산의 결과가 외부의 간섭에 관계없이(명령이 실행되다가 중단되는 경우) 전체가 완료되든지 전혀 실행되지 않은 상태로만 나타남 (All or Nothing)

    • 변수를 수정하는 일?

      1. 변수 값을 읽고
      2. 변수에 새로운 값을 쓰고
      3. 업데이트된 값을 저장

      → 각 단계 사이에 시간적 텀이 발생

      → 병렬 또는 동시적으로 실행될 때 공유되는 변수에 대해 변경사항이 덮어씌워질 수 있음

      (동시성 오류)

      → 공유된 이 변수는 임계영역(critical section)

  • 원자성 위반

    • 임계영역에 2개 이상의 스레드가 접근하여 공유된 자원에 대한 변경사항이 유실되는 경우
    • 동기화 메커니즘: 공유된 자원이 각 스레드가 동일하게 읽고 쓸 수 있게 하는 방법
      • 스레드 한정(제한)

        • 코루틴이 단일 스레드에서만 동작하도록 (newSingleThreadContext())
        • actor
          • = 코루틴 + 채널

          • 송신자(producer) - 수신자(consumer) 모델

            • 수신자 구현: 특정 CoroutineContext로 실행 가능

              val consumer = actor<T>(CoroutineContext) {
              	// implement for consumer
              }
              
            • 송신자 구현: 수신자와 다르게 코루틴에서 실행 가능

              async(CommonPool) {
              	consumer.send()   // call consumer as producer
              }
              
          • actor를 스레드 한정(제한)과 같이 사용하면 좋음

            • actor는 특정 스레드 풀에서 실행할 수 있도록 CorutineContext를 지정할 수 있으므로, newSingleThreadContext()를 사용하면 스레드 한정 기법을 이용할 수 있음
          • 그 밖에 액터에 대한 추가 팁

            • Buffered actor: capacity 매개변수를 빌더에 전달하여 구현 가능
            • CoroutineContext 지정 가능
              • 앞선 예제에서는 스레드 한정을 보여주기 위해 newSingleThreadContext()를 전달했지만, newFixedThreadPoolContext() 등 자유롭게 지정 가능
            • CoroutineStart: 액터의 동작 방식 변경 가능
      • 상호배제 (MUTual EXclusion):

        • 한 번에 하나의 코루틴만 코드 블록을 실행할 수 있도록 하는 동기화 메커니즘
        • Java의 synchronized
        • Kotlin의 Mutext: Non-blocking synchronized
      • volatile 변수

        Untitled

        • JVM 스레드 캐시
        • 스레드에 대해 변수의 가시성(visibility)을 보장
          • 아래 2가지 조건을 만족할 경우 사용 가능

            • 변수 값의 변경은 현재 상태에 의존하지 않는다.
            • 휘발성 변수는 다른 변수에 의존하지 않으며, 다른 변수도 휘발성 변수에 의존하지 않는다.
          • 공유 자원에 대해 한 스레드에서는 쓰기만 하고, 다른 스레드에서 읽기만 할 때 적합

          • 2개 이상의 스레드가 동시에 공유 자원에 대한 읽기, 쓰기를 모두 할 경우 부적합

            ex) a 변수를 1 스레드와 2 스레드가 모두 0으로 읽은 상태에서, 각각 +1을 경우 결국 메인 메모리에 저장되는 a 변수의 값은 1

          • 성능 저하 이슈

            • 캐시 사용 안함
            • JVM Instruction Reordering 불가능
      • atomic 데이터 타입

        • JVM 레벨에서 제공하는 메모리 차원에서의 원자성 회피 방법