Android

[Android] 경쟁 상태(Race Condition)란?

참깨빵위에참깨빵_ 2024. 9. 29. 22:11
728x90
반응형

아래는 경쟁 상태를 설명하는 영문 위키백과다.

 

https://en.wikipedia.org/wiki/Race_condition

 

Race condition - Wikipedia

From Wikipedia, the free encyclopedia When a system's behavior depends on timing of uncontrollable events Race condition in a logic circuit. Here, ∆t1 and ∆t2 represent the propagation delays of the logic elements. When the input value A changes from l

en.wikipedia.org

경쟁 조건은 시스템의 실질적인 동작이 제어할 수 없는 다른 이벤트의 순서, 타이밍에 의존해서 예기치 않거나 일관되지 않은 결과를 초래하는 시스템 상태를 말한다. 가능한 동작 중 하나 이상이 바람직하지 않은 경우 버그가 된다...(중략)...특히 논리 회로나 멀티 쓰레드, 분산 소프트웨어 프로그램에서 경쟁 조건이 발생할 수 있다. 상호 배제를 사용하면 분산 소프트웨어 시스템에서 경쟁 조건을 막을 수 있다...(중략)...동시 실행되는 코드 경로가 여러 개 있을 때 소프트웨어에서 경합 조건이 발생할 수 있다. 여러 코드 경로가 예상과 다른 시간이 걸리면 예상과 다른 순서로 완료되서 예기치 않은 동작으로 인해 버그가 발생할 수 있다. 심각한 경합 조건은 잘못된 실행, 소프트웨어 버그를 유발한다. 치명적 경쟁 조건은 프로세스나 쓰레드가 일부 공유상태에 의존할 때 발생한다. 공유 상태에 대한 작업은 상호배타적이어야 하는 중요한 섹션에서 수행된다...(중략)...경함 조건은 최종 결과가 비결정적이고 간섭하는 쓰레드 간의 상대적 타이밍에 따라 달라지기 때문에 재현, 디버깅이 어려울 수 있다. 따라서 이런 성격의 문제는 디버그 모드로 실행하거나 로그 추가, 디버거를 연결하면 사라질 수 있다. 디버깅 중에 이렇게 사라지는 버그를 하이젠버그라고 한다. 따라서 신중한 소프트웨어 설계를 통해 경쟁 조건을 피하는 게 좋다

 

경쟁 조건은 안드로이드에서도 발생할 수 있는 문제다. 어떤 메모리 위치를 대상으로 둘 이상의 읽기 or 쓰기 작업이 거의 동시 실행되어 어떤 작업이 먼저 완료될지 예측할 수 없는 경우에 발생할 수 있다. 안드로이드에선 아래 경우에 발생할 수 있다.

 

  • 비동기 작업 : 쓰레드, 코루틴 등을 쓸 때 여러 쓰레드가 공유 리소스에 접근할 때
  • UI 업데이트 : 백그라운드 쓰레드에서 UI를 직접 업데이트하려고 할 때
  • 싱글톤 패턴 : 멀티 쓰레드 환경에서 싱글톤 인스턴스를 만들 때 적절한 동기화가 없는 경우
  • 쉐어드 프리퍼런스 : 여러 쓰레드에서 동시에 읽기 / 쓰기 작업을 수행할 때
  • DB : 동시에 여러 DB 트랜잭션이 실행될 때
  • 네트워크 요청 : 여러 쓰레드에서 동시에 네트워크 요청을 처리할 때
  • 서비스 시작 / 중지 : 서비스의 생명주기 함수가 동시 호출될 때
  • 브로드캐스트 리시버 : 여러 리시버가 동시에 같은 리소스에 접근할 때

 

텍스트뷰가 있고 두 쓰레드에서 이 텍스트뷰에 각각 1, 2라는 숫자를 표시하라고 동시에 명령을 내린다면 텍스트뷰는 결국 어떤 숫자를 표시해야 하는가?

이런 경우가 발생하지 않게 조심해야 한다. 안드로이드에서 경쟁 조건이 발생하지 않게 하려면 아래 방법들을 고려해볼 수 있다.

 

방법 설명
동기화 매커니즘 사용 synchronized를 메서드나 코드 블록에 써서
한 번에 하나의 쓰레드만 접근할 수 있게 하거나,
Lock 인터페이스를 써서 동기화를 세밀하게 제어한다
thread-safe한 자료구조 활용 ConcurrentHashMap 등 동시성을 지원하는 컬렉션을
사용하거나, AtomicBoolean 등 atomic 타입을 써서
원자적 연산을 수행한다
핸들러 사용 메인 쓰레드(UI 쓰레드)와 백그라운드 쓰레드 간 통신을
안전하게 처리한다
쓰레드 풀 사용 ExecutorService를 써서 동시성을 제어한다
불변 객체 사용 원천적으로 동시성 문제를 방지할 수 있는 방법이다
volatile 키워드 사용 변수의 가시성을 보장해서 멀티 쓰레드 환경에서의
일관성을 유지한다
SingleThreadExecutor 사용 순차적 실행이 필요한 작업에 사용한다
코루틴 활용 비동기 프로그래밍을 단순화하고 동시성 관리를 개선한다

 

ConcurrentHashMap은 코틀린 공식문서에만 있을 줄 알았는데 의외로 안드로이드 디벨로퍼에도 공식문서가 존재한다.

 

https://developer.android.com/reference/kotlin/java/util/concurrent/ConcurrentHashMap

 

ConcurrentHashMap  |  Android Developers

 

developer.android.com

 

Atomic이 붙은 타입은 멀티 쓰레드 환경의 중요 개념인 동시성, 가시성, 원자성 중 원자성을 보장하기 위해 설계된 타입이다. 하나의 변수에 원자적 연산이 필요하거나 원자적 접근을 보장할 때 사용할 수 있다.

원자적 연산은 읽기, 쓰기, 갱신 등 작업이 중단 없이 완전하게 실행되는 걸 말한다. 원자성을 더 알아보는 건 이 포스팅의 범위를 넘기 때문에 생략한다.

반응형