본문 바로가기

hayee Study/코딩_c#

[C#] ReaderWriterLockSlim 사용법 (멀티 스레드 환경에서 파일 쓰기)

반응형

 

안녕하세요 hayee 입니다.

 

멀티 스레드 환경에서 로그 쓰기를 위해 파일에 접근하는데, 특정 로그가 누락되는 이슈가 있었습니다. 

파일 쓰기 전 ReaderWriterLockSlim 을 사용하여 멀티스레드 환경에서 파일 쓰기를 할 때 한 개의 스레드만 접근 가능하도록 하여 이를 해결하였습니다.


◈ 예제 소스 

public partial class Form1 : Form
{
    Thread m_th1, m_th2;

    public Form1()
    {
        InitializeComponent();
    }

    private void btnWrite_Click(object sender, EventArgs e)
    {
        m_th1 = new Thread(() => StartThread1());
        m_th1.Name = "test thread 1";
        m_th1.IsBackground = true;
        m_th1.Start();

        Thread.Sleep(100);

        m_th2 = new Thread(() => StartThread2());
        m_th2.Name = "test thread 2";
        m_th2.IsBackground = true;
        m_th2.Start();
    }

    private void StartThread1()
    {
        int nCount = 0;

        while (true)
        {
            string slog = string.Format("스레드01 - 테스트 로그 / Count:{0}", nCount++);
            Log.Writelog(slog);

            if (nCount > 200)
                nCount = 0;

            Thread.Sleep(200);
        }
    }

    private void StartThread2()
    {
        int nCount = 0;

        while (true)
        {
            string slog = string.Format("스레드02 - 테스트 로그 / Count:{0}", nCount++);
            Log.Writelog(slog);

            if (nCount > 200)
                nCount = 0;

            Thread.Sleep(250);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (m_th1 != null)
        {
            m_th1.Abort();
            m_th1 = null;
        }

        if (m_th2 != null)
        {
            m_th2.Abort();
            m_th2 = null;
        }
    }
}

class Log
{
    static readonly string m_sFolderName = "\\LOG\\";
    //static readonly ReaderWriterLockSlim m_rwLock = new ReaderWriterLockSlim();

public static void Writelog(string logMsg)
{
    try
    {
        string sLogFilePath = Directory.GetCurrentDirectory() + m_sFolderName + DateTime.Now.ToString("yyyyMM");

        if (!Directory.Exists(sLogFilePath))
        {
            Directory.CreateDirectory(sLogFilePath);
        }

        string sFile = sLogFilePath + "\\TestFile_" + DateTime.Now.ToString("yyyyMMdd") + ".log";

        if (!File.Exists(sFile))
        {
            using (StreamWriter sw = File.CreateText(sFile))
            {
                ;
            }
        }

        //m_rwLock.EnterWriteLock();

        using (StreamWriter sw = File.AppendText(sFile))
        {
            string sLog = logMsg.Replace("\n", "");

            sw.Write(System.DateTime.Now.ToString("HH:mm:ss.fff: "));
            sw.WriteLine(sLog);
            sw.Close();
        }
    }
    catch (Exception ex)
    {
        Trace.WriteLine("Exception Error : " + ex.Message);         
    }
    //finally
    //{
    //    m_rwLock.ExitWriteLock();
    //}
    }
}

1. 버튼을 누르면 2개의 스레드가 생성된다.

2. 두 개의 스레드는 주기적으로 파일에 Write 동작을 한다.

3. ReaderWriterLockSlim 을 사용하지 않았을 경우 주기적으로 출력창에 Exception error 가 발생함을 확인할 수 있었다.

(Error >> TestFile_20230210.log' 파일은 다른 프로세스에서 사용 중이므로 프로세스에서 액세스할 수 없습니다.)

 

 

◈ 실행 결과

소스 코드 빌드 결과

 

4.  ReaderWriterLockSlim 관련 주석을 풀고 다시 테스트할 경우 관련 에러가 발생하지 않는 것을 확인할 수 있다.

 

 

 

 

# 틀린 부분이 있다면 댓글 부탁드립니다. #

# 댓글 달아주시면 늦게라도 블로그 방문하도록 할게요! 감사합니다. #

 

 

 

728x90
반응형