내용 보기
작성자
관리자 (IP : 106.247.248.10)
날짜
2024-07-29 08:22
제목
[C#] [스크랩] async 메서드에서의 lock/Monitor.Enter/Exit 잠금 처리
| Monitor 잠금은 스레드를 기억하는 유형입니다. 그래서, lock을 보유한 스레드만이 해제를 할 수 있습니다. 가령, 다음과 같이 다른 스레드에서 lock을 해제하려고 하면, internal class Program
{
    static object _obj = new object();
    static void Main(string[] args)
    {
        Monitor.Enter(_obj); // lock을 획득
        
        Thread t = new Thread(() =>
        {
            Monitor.Exit(_obj); // 다른 스레드에서 lock을 해제
        });
        t.Start();
        t.Join();
    }
}
 Unhandled exception. System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code. at System.Threading.Monitor.Exit(Object obj) at Program.<>c.<Main>b__1_0() 
 
 internal class Program
{
    static object _obj = new object();
    static void Main(string[] args)
    {
        Console.WriteLine("Lock++");
        Monitor.Enter(_obj);
        Console.WriteLine("Lock++");
        Monitor.Enter(_obj); // 2번 잠금
        Thread t = new Thread(() =>
        {
            Monitor.Enter(_obj); // 다른 스레드에서 lock을 얻으려고 시도
            Console.WriteLine("Thread 1");
            Monitor.Exit(_obj);
        });
        t.Start();
        Console.WriteLine($"{DateTime.Now} Lock--");
        Monitor.Exit(_obj); // 한 번 잠금을 해제
        Thread.Sleep(5000);
        Console.WriteLine($"{DateTime.Now} Lock--");
        Monitor.Exit(_obj); // 두 번 잠금을 해제 - 이 시점에 "Thread 1"이 출력됨
        t.Join();
    }
}
 Lock++ Lock++ 2024-07-26 오후 18:44:40 Lock-- 2024-07-26 오후 18:44:45 Lock-- // 5초 후 2번째 잠금이 해제되고 나서야 "Thread 1"이 출력됨 Thread 1 
 
 C# - Mutex의 비동기 버전 ; https://www.sysnet.pe.kr/2/0/13157 
 internal class Program
{
    static object _obj = new object();
    static async Task Main(string[] args)
    {
        lock (_obj)
        {
            // error CS1996: Cannot await in the body of a lock statement
            await Task.Delay(2000);
        }
    }
}
 internal class Program
{
    static object _obj = new object();
    static async Task Main(string[] args)
    {
        Monitor.Enter(_obj);
        await Task.Delay(2000);
        Monitor.Exit(_obj); // 실행 시 오류
    }
}
 Unhandled exception. System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code. at System.Threading.Monitor.Exit(Object obj) at Program.Main(String[] args) at Program.<Main>(String[] args) 
 public partial class Form1 : Form
{
    object _obj = new object();
    public Form1()
    {
        InitializeComponent();
    }
    private async void Form1_Load(object sender, EventArgs e)
    {
        bool lockTaken = false;
        try
        {
            Monitor.Enter(_obj, ref lockTaken);
            await Task.Delay(2000);
        }
        finally
        {
            if (lockTaken)
            {
                Monitor.Exit(_obj);
            }
        }
    }
}
 private async void Form1_Load(object sender, EventArgs e)
{
    lock (_obj) // 컴파일 오류: error CS1996: Cannot await in the body of a lock statement
    {
        await Task.Delay(2000);
    }
}
 private async void Form1_Load(object sender, EventArgs e)
{
    bool lockTaken = false;
    try
    {
        Monitor.Enter(_obj, ref lockTaken);
        await Task.Delay(2000).ConfigureAwait(false);
    }
    finally
    {
        if (lockTaken)
        {
            Monitor.Exit(_obj); // 실행 시 오류: System.Threading.SynchronizationLockException: 'Object synchronization method was called from an unsynchronized block of code.'
        }
    }
}
 
 namespace WinFormsApp1;
public partial class Form1 : Form
{
    SemaphoreSlim _sem = new SemaphoreSlim(1);
    public Form1()
    {
        InitializeComponent();
    }
    private async void Form1_Load(object sender, EventArgs e)
    {
        _sem.Wait(); // Main 스레드에서 lock 획득
        new Thread(() =>
        {
            System.Diagnostics.Trace.WriteLine($"[{DateTime.Now}] --------------------- Thread called");
            _sem.Wait(); // 사용자 스레드에서 lock 획득 시도
            try
            {
                System.Diagnostics.Trace.WriteLine($"[{DateTime.Now}] --------------------- got Semaphore");
                Thread.Sleep(2000);
            }
            finally
            {
                _sem.Release();
            }
        })
        { IsBackground = true }.Start();
        try
        {
            await Task.Delay(5000).ConfigureAwait(false); // 5초 후에,
        } finally
        {
            _sem.Release(); // 스레드풀의 스레드에서 lock 해제
        }
    }
}
 | 
출처1
https://www.sysnet.pe.kr/2/0/13697
출처2