공부/게임서버

ReaderWriterLock

samosa 2024. 11. 16. 18:59

ReaderWriterLockSlim을 게임 보상 시스템(Reward 클래스) 같은 예시 상황으로 설명해보겠다. 이 클래스는 다중 스레드 환경에서 게임 보상 데이터에 대한 안전한 동시 접근을 보장해야 한다. 예를 들어, 수많은 플레이어가 게임에서 보상을 확인하는 동시에, 관리자나 시스템이 보상 데이터를 수정하는 경우를 고려할 수 있다.

예시 상황

게임 서버에는 플레이어가 다양한 보상 데이터를 읽고 확인할 수 있는 Reward 클래스가 있다. 동시에, 관리자는 이벤트나 게임 업데이트로 인해 보상 데이터를 수정할 수 있다. 이 경우 다수의 플레이어가 보상을 확인할 때 성능을 최적화하기 위해 여러 스레드가 보상 데이터를 읽을 수 있어야 하지만, 보상 데이터를 수정할 때는 데이터를 보호하기 위해 쓰기 잠금이 필요하다.

Reward 클래스와 ReaderWriterLockSlim 적용

using System;
using System.Threading;
using System.Threading.Tasks;

public class Reward
{
    private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    private int _goldReward = 100;

    // 보상을 읽는 메서드 (플레이어가 보상 확인)
    public void CheckReward(string playerName)
    {
        _lock.EnterReadLock();
        try
        {
            Console.WriteLine($"{playerName}이(가) 보상을 확인 중입니다... (Gold Reward: {_goldReward})");
            Thread.Sleep(500); // 읽기 작업 시뮬레이션
        }
        finally
        {
            _lock.ExitReadLock();
            Console.WriteLine($"{playerName}이(가) 보상 확인을 완료했습니다.");
        }
    }

    // 보상을 수정하는 메서드 (관리자나 시스템이 보상 업데이트)
    public void UpdateReward(int newReward)
    {
        _lock.EnterWriteLock();
        try
        {
            Console.WriteLine($"보상을 {_goldReward}에서 {newReward}로 업데이트 중...");
            _goldReward = newReward;
            Thread.Sleep(1000); // 쓰기 작업 시뮬레이션
            Console.WriteLine($"보상이 업데이트되었습니다. (Gold Reward: {_goldReward})");
        }
        finally
        {
            _lock.ExitWriteLock();
            Console.WriteLine("보상 업데이트가 완료되었습니다.");
        }
    }
}

public class Program
{
    public static async Task Main(string[] args)
    {
        Reward reward = new Reward();

        // 여러 플레이어가 동시에 보상 확인
        Task reader1 = Task.Run(() => reward.CheckReward("Player 1"));
        Task reader2 = Task.Run(() => reward.CheckReward("Player 2"));
        Task reader3 = Task.Run(() => reward.CheckReward("Player 3"));

        // 관리자나 시스템이 보상을 업데이트
        Task writer = Task.Run(() => reward.UpdateReward(200));

        await Task.WhenAll(reader1, reader2, reader3, writer);
        Console.WriteLine("모든 작업이 완료되었습니다.");
    }
}

설명

  1. CheckReward 메서드:
    • 여러 플레이어가 동시에 보상 데이터를 확인할 수 있도록 EnterReadLock()을 사용해 읽기 잠금을 건다.
    • 읽기 작업은 다른 읽기 작업과 충돌하지 않으므로, 여러 스레드가 동시에 보상을 확인할 수 있다.
  2. UpdateReward 메서드:
    • 보상 데이터를 수정할 때는 EnterWriteLock()을 사용해 쓰기 잠금을 건다.
    • 쓰기 잠금이 설정되면 다른 모든 읽기 및 쓰기 작업은 대기 상태가 되며, 데이터 무결성이 보장된다.
  3. 실행 흐름:
    • Task.Run()으로 여러 작업을 비동기적으로 실행해, 다수의 플레이어가 동시에 보상을 읽는 상황을 시뮬레이션한다.
    • 관리자가 보상 데이터를 수정하면, 읽기 스레드는 수정이 완료될 때까지 대기 상태가 된다.

예시 상황에서의 장점

  • 읽기 최적화: 여러 플레이어가 동시에 보상 데이터를 확인할 수 있어 성능이 향상된다.
  • 쓰기 보호: 보상 데이터 수정 시에는 독점 잠금이 걸려 데이터 무결성이 보장된다.
  • 업데이트 후 일관성 유지: ReaderWriterLockSlim을 사용함으로써 읽기 작업 중에 쓰기 작업이 시작되면 읽기 스레드들이 일관된 데이터 상태를 보장받을 수 있다.

이러한 방식은 읽기 작업이 빈번하고 쓰기 작업이 상대적으로 적은 시나리오, 예를 들어 게임에서 보상 데이터를 다루는 상황에서 매우 적합하다.