그린티라떼
개발공간
그린티라떼
전체 방문자
오늘
어제
  • 분류 전체보기 (26)
    • unity (6)
      • 개발 (4)
      • iTween (0)
      • error (2)
    • 게임서버 (5)
    • C++ (7)
      • 문법 (5)
      • 알고리즘 (2)
    • C# (5)
    • CS지식 (1)
    • 기타 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • regex
  • 정규 표현식
  • cs지식
  • c#
  • 일반화컬렉션
  • inline 함수
  • 일반화
  • interface
  • 컨테이너
  • object
  • Gradle build failed
  • Container
  • unity
  • 다중상속의 문제점
  • Delegate
  • Dynamic
  • 유니티 빌드 에러
  • delegate chain
  • 함수호출
  • 제네릭
  • cout 스트림 버퍼
  • Functions
  • 함수 호출 오버헤드
  • 형식매개변수의 제약
  • property
  • 유니티
  • 데이터타입
  • 메모리영역
  • C++
  • var

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
그린티라떼

개발공간

게임서버

ReaderWriterLock 구현 연습

2020. 12. 1. 02:55
namespace ServerCore
{
    //재귀적 락을 허용할지 (yes) writeLock ->writeLock (ok) ,writelock->readlock (ok) ,readlock ->writelock (no)
    //재귀적 락을 허용할지 (NO)
    //스핀락 정책 (5000번 ->Yield)
    class Lock
    {
        const int EMPTY_FLAG = 0x00000000;
        const int WRITE_MASK = 0x7FFF0000;
        const int READ_MASK = 0x0000FFFF;
        const int MAX_SPIN_COUNT = 5000;

        // [Unused (1비트)] [WriteThreadId (15비트)] [ReadCount (16비트)]
        int flag= EMPTY_FLAG;
        int writeCount = 0;  //(yes)

        public void WriteLock()
        {
            //동일 스레드가 writeLcok을 이미 흭득하고 있느지 확인 //(yes)
            int lockThreadId = (flag & WRITE_MASK) >> 16;  //(yes)
            if (Thread.CurrentThread.ManagedThreadId == lockThreadId)  //(yes)
            {
                writeCount++;   //(yes)
                return;  //(yes)
            }

            //아무도 WriteLock Or ReadLock을 흭득하고 있지 않을 때, 경합해서 소유권을 얻는다.
            //
            //16비트만큼 밀어줘서 WriteThreadId를 사용할 수 있게 그리고 & WRITE_MASK 함으로써 쓸모없는 부분 다 0으로 바꿈
            int desired = (Thread.CurrentThread.ManagedThreadId << 16) & WRITE_MASK;

            while (true)
            {
                for(int i=0; i < MAX_SPIN_COUNT; i++)
                {
                    //시도를 해서 성공하면 return

                    //if (flag == EMPTY_FLAG) //아무도 락이 없는 상황
                    //    flag = desired; //WriteThreadI에 자신의 Id를 채워주고싶음
                    // But 멀티스레드환경에서 스레드들이 동시에 if문을 실행하면 문제 생김 그래서 인터락드써야함
                    if (Interlocked.CompareExchange(ref flag, desired, EMPTY_FLAG) == EMPTY_FLAG)
                    {
                        writeCount = 1;  //(yes)
                        return;
                    }
                }

                Thread.Yield();
            }
        }
        public void WriteUnlock()
        {
            int lockCount = --writeCount;  //(yes)  무조건 언락 하는것이 아니라 writeCount가 0이면 언락해드림
            if (lockCount ==0)  //(yes)
                //당연한 말이지만 WriteLock한 애만 언락 가능 
                //이건 초기상태로 만들면 됨
                Interlocked.Exchange(ref flag, EMPTY_FLAG);

        }
        public void ReadLock()  //상호 배타가 아님!
        {
            //동일 스레드가 writeLcok을 이미 흭득하고 있느지 확인 //(yes)
            int lockThreadId = (flag & WRITE_MASK) >> 16;  //(yes)
            if (Thread.CurrentThread.ManagedThreadId == lockThreadId)  //(yes)
            {
                Interlocked.Increment(ref flag);   //(yes) 리드카운트만 1 늘림
                return;  //(yes)
            }

            //아무도 WriteLock을 흭득하고 있지 않으면, ReadCount를 1 늘린다
            while (true)
            {
                for(int i=0; i < MAX_SPIN_COUNT; i++)
                {
                    //if ((flag & WRITE_MASK) == 0) //아무도 WriteLock을 흭득하고있지 않다는 의미
                    //{
                    //    flag += 1; //이 방법도 멀티스레드환경에서 문제있음, 여기서 다른애가 WriteLock을 하면 [WriteThreadI)] [ReadCount] 둘다에 접근됨;;
                    //    return;
                    //}
                    int expected = (flag & WRITE_MASK);
                    if (Interlocked.CompareExchange(ref flag, expected + 1, expected) == expected)
                        return;
                }

                Thread.Yield();
            }

        }
        public void ReadUnlock()
        {
            Interlocked.Decrement(ref flag); //그냥 1줄여주면 끝
        }

        //writelock 하고 readlock 하면  readUnlock 먼저하고 writeUnlock을 해야함

    }
}

 

 

 

 

 

namespace ServerCore
{
    class Program
    {
        static volatile int count = 0;
        static Lock _lock = new Lock();

        static void Main(string[] args)
        {
            Task t1 = new Task(delegate ()
             {
                 for (int i = 0; i < 100000; i++)
                 {
                     _lock.WriteLock();
                     count++;
                     _lock.WriteUnlock();
                 }
             });
            Task t2 = new Task(delegate ()
            {
                for (int i = 0; i < 100000; i++)
                {
                    _lock.WriteLock();
                    count--;
                    _lock.WriteUnlock();
                }
            });

            t1.Start();
            t2.Start();
            Task.WaitAll(t1, t2);
            Console.WriteLine(count);

        }
    }
}

 

결과 값 : 0

'게임서버' 카테고리의 다른 글

하드웨어 최적화  (0) 2020.11.30
캐시 이론  (0) 2020.11.30
컴파일러 최적화  (0) 2020.11.30
쓰레드 기초  (0) 2020.11.30
    '게임서버' 카테고리의 다른 글
    • 하드웨어 최적화
    • 캐시 이론
    • 컴파일러 최적화
    • 쓰레드 기초
    그린티라떼
    그린티라떼

    티스토리툴바