코루틴

    [Kotlin] 코루틴 세마포어(Semaphore) 사용해 공유 자원에 대한 접근 제한하기

    세마포어(Semaphore)란? 세마포어란 멀티 스레드 환경 혹은 멀티 프로세스 환경에서 공유 자원에 대한 접근을 일부 스레드 혹은 프로세스로 제한하기 위해 사용되는 방법이다. 코루틴 라이브러리 또한 이러한 세마포어를 구현한 Semaphore 객체를 가지고 있는데, 이 Semaphore 객체는 허락을 받은 일부 코루틴만 임계 영역(Critical Area)에 접근할 수 있도록 한다. Semaphore 객체를 쉽게 설명하기 위해, 일반적으로 Semaphore 객체가 가진 '허락(permit)'을 키에 비유해보자. Semaphore 객체는 여러 개의 키를 가지고 있고, 이 키의 개수는 개발자에 의해 설정된다. 이 키들은 바로 임계 영역에 접근할 수 있는 키이며, 이 키를 빌린 코루틴만 임계 영역에 접근할 수..

    [Kotlin] Mutex 객체 사용해 코루틴에 락 걸기

    코루틴에서의 락우리는 이전 글에서 코루틴에서 ReentrantLock 사용해 락을 걸게 될 경우, 락이 해제 되기 전에 코루틴의 스레드 양보가 일어나면 데드락이 발생할 수 있다는 것을 알아보았다. [Kotlin] 코루틴을 사용할 때 ReentrantLock을 사용해 락을 걸면 안되는 이유시작하며 우리는 이전 글에서 ReentrantLock을 사용해 락을 걸고 해제해보면서, 여러 스레드가 동시에 접근해도 안전한 임계영역(Critical Area)을 만드는 방법에 대해 살펴봤다. [Kotlin] ReentrantLock 사용kotlinworld.com그렇다면, 코루틴에서 안전한 임계 영역(Critical Area)을 만들기 위해서는 어떻게 해야 할까? 바로 젯브레인의 코루틴 라이브러리(kotlinx.coro..

    [Kotlin] 코루틴을 사용할 때 ReentrantLock을 사용해 락을 걸면 안되는 이유

    시작하며 우리는 이전 글에서 ReentrantLock을 사용해 락을 걸고 해제해보면서, 여러 스레드가 동시에 접근해도 안전한 임계영역(Critical Area)을 만드는 방법에 대해 살펴봤다. [Kotlin] ReentrantLock 사용해 락 걸고 해제하기 ReentrantLock 사용해 락 걸기 코틀린에서는 기본적으로 자바의 ReentrantLock 클래스를 사용해 락을 걸고 해제할 수 있다. ReentrantLock을 사용해 락을 걸고 해제하는 방법은 간단하다. 임계영역(Critical Are kotlinworld.com 이번 글에서는 ReentrantLock을 사용해 코루틴에서 임계 영역을 만들 때의 문제점과 ReentrantLock을 사용해도 되는 경우와 안 되는 경우에 대해 알아본다. 코루틴에..

    [Testing Coroutines] 코루틴 비동기 테스트가 어려운 이유

    코루틴이 멀티 스레드 환경에서 실행될 때 테스트가 어려운 이유 코루틴은 일반적으로 멀티 스레드 환경에서 비동기적으로 실행된다. 이 때문에 멀티 스레드 환경의 문제가 그대로 테스트에 나타난다. 그 대표적인 문제는 다음과 같다. 1. 함수 호출 순서 문제 2. 경쟁 상태 문제 3. 코루틴이 사용하는 디스패처 문제 함수 호출 순서 문제 멀티 스레드 환경에서 실행되는 함수들은 함수의 호출 순서를 파악하기 어렵다. 코루틴을 테스트 할 때도 이 문제가 나타나며, 병렬성으로 인해 실행을 코루틴이 실행되기 전에 다른 코루틴이 실행될 수 있다. 또한, 코루틴은 함께 실행되기 때문에 어떤 코드가 먼저 실행될지 파악하기 매우 어렵다. 예를 들어 하나의 코루틴이 일시 중단하게 되면 스레드를 다른 스레드가 사용할 수 있도록 양..

    [MockK] coEvery 사용해 목 객체의 일시 중단 함수에 대한 테스트 응답값 설정하기

    every를 사용해 응답값을 설정할 때의 문제점 이전 글에서 다루었던 UserProfileFetcher이 리모트 저장소로부터 데이터를 가져오는 I/O 작업을 한다고 가정하고, 함수를 모두 다음과 같이 일시 중단 함수로 바꿔보자. class UserProfileFetcher( private val userRepository: UserRepository, ) { suspend fun getUserProfileById(id: String): UserProfile { return UserProfile( id = id, name = userRepository.getNameByUserId(id) ) } } interface UserRepository { suspend fun saveUserName(id: Strin..