lock 을 하면 비동기를 사용할 수 없다.
정확히는 위험하다. ( lock(리소스) {작업} 식으로 사용할 때에는 아예 컴파일 에러가 난다. )
lock 은 다른 스레드에서 이 리소스에 접근하지 못하게 하는 기법이기 때문이다.
비동기 호출을 하게 되면 await 를 할 때마다 실행 중이던 작업이 중지되고 대기 상태가 되었다가 스레드 풀의 스레드 중 하나에서 실행이 되는데, 이때 스레드가 원래 lock 을 했던 스레드가 아닐 가능성이 매우 높기 때문에 이 리소스에 접근하지 못하게 되는 현상이 생겨날 수 있다.
아무튼 이런 이유 때문에 비동기 함수에서 lock 을 주의해서 써야 한다.

비동기에서 lock 을 사용하려면 SemaporeSlim 을 사용하면 된다.
SemaphoreSlim 은 lock 과는 달리 숫자만 카운팅한다.
lock이 한 리소스에 하나의 스레드만 리소스를 사용할 수 있게 하는 방법이라면,
SemaphoreSlim은 하나의 리소스에 대해 사용을 시작할 수 있는 숫자를 컨트롤할 수 있게 하는 방법이다.
사용법은 이렇다.
public static async Task Main()
{
var semaphore = new SemaphoreSlim(1); // 1개까지 허용
semaphore.Wait();
Console.WriteLine("semaphore lock");
semaphore.Release();
Console.WriteLine("semaphore lock release");
}
아래 코드를 보면 더 이해하기 쉬울 것 같다.
public static async Task Main()
{
var semaphore = new SemaphoreSlim(2); // 2개까지 허용
Console.WriteLine("0");
semaphore.Wait(); // count +1
Console.WriteLine("1");
semaphore.Wait(); // count +1
Console.WriteLine("2");
semaphore.Wait(); // count = 2 -> 사용 불가
Console.WriteLine("3"); // 출력되지 않음
}
semaphore slim 은 비동기 환경에서 사용할 수 있다는 장점이 있지만, 이런 단점도 있는것같다.
기존 lock 사용 시
public class InitTest
{
public static InitTest Instance;
public static async Task Main()
{
Instance = new();
lock (Instance)
{
Function();
}
}
public static void Function()
{
lock (Instance)
{
Console.WriteLine("process");
}
}
}
그리고 monitor 를 써도 스레드만 같으면 lock 때문에 문제가 생기는 일은 없다.
public class InitTest
{
public static InitTest Instance;
public static async Task Main()
{
Instance = new();
Monitor.Enter(Instance);
Function();
Monitor.Exit(Instance);
}
public static void Function()
{
Monitor.Enter(Instance);
Console.WriteLine("process");
Monitor.Exit(Instance);
}
}
하지만 세마포를 쓰면 스레드 단위가 아니고, 카운트를 세는 기준이기 때문에 문제가 생긴다.
public class InitTest
{
public static SemaphoreSlim semaphore;
public static async Task Main()
{
semaphore = new SemaphoreSlim(1);
semaphore.Wait();
Function();
semaphore.Release();
}
public static void Function()
{
semaphore.Wait();
Console.WriteLine("process"); // 출력안됨
semaphore.Release();
}
}
'Server > C#' 카테고리의 다른 글
📚 xUnit 설치 & 사용법 정리 (0) | 2024.11.15 |
---|---|
안정적인 서버를 구현하기 위한 잡지식 (0) | 2024.03.22 |
맨날 헷갈리는 상속 오버라이딩 정리 (0) | 2024.01.02 |
딕셔너리 vs 해시테이블 (2) | 2023.11.28 |
진짜 오랫동안 삽질했던, 프로그램 비정상 종료 대처법 (0) | 2023.10.11 |
lock 을 하면 비동기를 사용할 수 없다.
정확히는 위험하다. ( lock(리소스) {작업} 식으로 사용할 때에는 아예 컴파일 에러가 난다. )
lock 은 다른 스레드에서 이 리소스에 접근하지 못하게 하는 기법이기 때문이다.
비동기 호출을 하게 되면 await 를 할 때마다 실행 중이던 작업이 중지되고 대기 상태가 되었다가 스레드 풀의 스레드 중 하나에서 실행이 되는데, 이때 스레드가 원래 lock 을 했던 스레드가 아닐 가능성이 매우 높기 때문에 이 리소스에 접근하지 못하게 되는 현상이 생겨날 수 있다.
아무튼 이런 이유 때문에 비동기 함수에서 lock 을 주의해서 써야 한다.

비동기에서 lock 을 사용하려면 SemaporeSlim 을 사용하면 된다.
SemaphoreSlim 은 lock 과는 달리 숫자만 카운팅한다.
lock이 한 리소스에 하나의 스레드만 리소스를 사용할 수 있게 하는 방법이라면,
SemaphoreSlim은 하나의 리소스에 대해 사용을 시작할 수 있는 숫자를 컨트롤할 수 있게 하는 방법이다.
사용법은 이렇다.
public static async Task Main()
{
var semaphore = new SemaphoreSlim(1); // 1개까지 허용
semaphore.Wait();
Console.WriteLine("semaphore lock");
semaphore.Release();
Console.WriteLine("semaphore lock release");
}
아래 코드를 보면 더 이해하기 쉬울 것 같다.
public static async Task Main()
{
var semaphore = new SemaphoreSlim(2); // 2개까지 허용
Console.WriteLine("0");
semaphore.Wait(); // count +1
Console.WriteLine("1");
semaphore.Wait(); // count +1
Console.WriteLine("2");
semaphore.Wait(); // count = 2 -> 사용 불가
Console.WriteLine("3"); // 출력되지 않음
}
semaphore slim 은 비동기 환경에서 사용할 수 있다는 장점이 있지만, 이런 단점도 있는것같다.
기존 lock 사용 시
public class InitTest
{
public static InitTest Instance;
public static async Task Main()
{
Instance = new();
lock (Instance)
{
Function();
}
}
public static void Function()
{
lock (Instance)
{
Console.WriteLine("process");
}
}
}
그리고 monitor 를 써도 스레드만 같으면 lock 때문에 문제가 생기는 일은 없다.
public class InitTest
{
public static InitTest Instance;
public static async Task Main()
{
Instance = new();
Monitor.Enter(Instance);
Function();
Monitor.Exit(Instance);
}
public static void Function()
{
Monitor.Enter(Instance);
Console.WriteLine("process");
Monitor.Exit(Instance);
}
}
하지만 세마포를 쓰면 스레드 단위가 아니고, 카운트를 세는 기준이기 때문에 문제가 생긴다.
public class InitTest
{
public static SemaphoreSlim semaphore;
public static async Task Main()
{
semaphore = new SemaphoreSlim(1);
semaphore.Wait();
Function();
semaphore.Release();
}
public static void Function()
{
semaphore.Wait();
Console.WriteLine("process"); // 출력안됨
semaphore.Release();
}
}
'Server > C#' 카테고리의 다른 글
📚 xUnit 설치 & 사용법 정리 (0) | 2024.11.15 |
---|---|
안정적인 서버를 구현하기 위한 잡지식 (0) | 2024.03.22 |
맨날 헷갈리는 상속 오버라이딩 정리 (0) | 2024.01.02 |
딕셔너리 vs 해시테이블 (2) | 2023.11.28 |
진짜 오랫동안 삽질했던, 프로그램 비정상 종료 대처법 (0) | 2023.10.11 |