싱글코어를 가지는 CPU가 여러 프로그램을 동시에 띄어서 실행시킬 수 있는 방법은 아주 짧은 시간동안 여러 프로그램(프로세스)들을 옮겨다니며 실행하면 된다. 이렇게 하면 동시에 여러 프로그램들이 동작하는 것처럼 보인다.CPU의 코어 하나의 성능을 높이지 말고 코어의
위와 같이 디버그 모드로 실행 중 Break All 버튼을 누르면 메인쓰레드에서 Join()함수 라인에서 멈춰있는 것을 볼 수 있다.그리고 test로 이름지어준 쓰레드로 바꿔주면 백그라운드에서 실행중인 MainThread() 부분에 화살표가 이동하는 것을 볼 수 있다.
Release 모드로 프로그램을 실행하게 되면 컴파일러가 지멋대로 코드최적화를 할 수 있다. 위 경우엔 \_stop이 true가 되었음에도 task가 끝나지 않고 무한히 대기하는 모습을 보여주는데 while(\_stop == false) 부분이로 바뀐게 그 이유라고 한
가장 최근에 사용된 그 변수가 또다시 사용될 확률이 높다방금 접근한 변수와 인접한 주소에 있는 변수에 접근할 확률이 높다쓰레드마다 각각의 코어로 실행되고 있고, 코어마다 ALU, 캐시를 가진다.직원들은 주문이 변경되면 바로 주문현황판(RAM)에 기입하지 않고 (거리가
컴파일러에 이어서 하드웨어도 우리를 위해 최적화를 해주고 있는데, 이 때문에 서로 연관성이 없는 코드끼리 속도 향상을 위해 순서를 바꿀 수 있다.순서를 강제할 수 있는 방법은 메모리 배리어를 사용하는 것이다.위 코드으 경우 Thread.MemoryBarrier를 사용하
num++;는 다음과 같이 세 단계에 걸쳐 일어난다.따라서 쓰레드가 두개있고 각각의 쓰레드에서 다음과 같은 코드를 수행하면num의 결과값이 0이 아니게 된다.왜냐하면 num이 바로 1씩 증가/감소하지 않고 세 단계를 거치기 때문에 그런것이다.이해를 쉽게 하기 위해 i&
두 개 이상의 작업이 서로 상대방의 작업이 끝나기 만을 기다리고 있기 때문에 결과적으로 아무것도 완료되지 못하는 상태를 가리킨다. 각각의 클래스에 존재하는 \_lock 변수를 열쇠라고 생각하고, lock(\_lock) 부분을 문고리라고 생각하자.위 코드에서 두 개의 쓰
Interlocked.CompareExchange(ref \_locked, desired, expected)\_locked와 expected를 비교해서 같으면 desired를 \_locked에 대입하고 이전값(expected)을 반환한다.간단하게 말해서 락을 획득할 때
무조건 xms 휴식조건부 양보. 우선순위가 자신보다 낮으면 양보할 수 없지만, 같거나 높은 쓰레드가 있으면 그 쓰레드에게 양보한다.지금 실행 가능한 쓰레드가 있으면 실행하고, 없으면 자신을 실행Context Switching이란 멀티 프로세스 환경에서 CPU가 어떤 하
SpinLock에 이어서 또 다른 방법은 계속 기다리는 것이 아닌, 자신은 다른 일을 하다가 lock이 풀리게 되면 그때 알림을 받아서 lock을 획득하는 방식이 있다.이 일을 AutoResetEvent가 하게되는데 철도 건널목에 비유를 하면 WaitOne이라는 차단기
설명 코드
설명 쓰레드마다 고유하게 접근 가능한 전역변수. 서로 의존성이 묶여있는(lock을 걸 필요가 있는) 데이터를 각자의 TLS로 갖고 가는 것이 아닌 buffer와 같이 독립적으로 사용할 수 있는 데이터를 TLS에 넣어두고 처리를 하게 되면 lock을 걸 때마다 부하가 걸리는 것을 최소화할 수 있다. TLS는 쓰레드끼리 경합없이 특정 쓰레드만 사용할 정보를...
설명 블록킹 계열 함수인 Accept() 함수를 사용하는 것은 그 라인에서 클라이언트가 연결 요청을 받을 때까지 계속 대기를 할 수 있기 때문에, 비동기적으로 처리를 하기 위해 AcceptAsync() 함수를 사용하도록 코드를 구성한다. ServerCore에서 Li
코드 Program.cs Session.cs Listener.cs
ServerCore 프로젝트 속성 -> Output type을 Class Library로 변경 Server 프로젝트 -> Add -> Project Reference -> ServerCore 체크해서 참조 DummyClient 프로젝트 -> Add -> Project Reference -> ServerCore 체크해서 참조 startup projects를...
코드 ServerCore Session RecvBuffer DummyClient GameSession Server GameSession
코드 ServerCore Session.cs SendBuffer Server ClientSession.cs DummyClient ServerSession.cs
코드 ServerCore Session.cs Server ClientSession.cs DummyClient ServerSession.cs
PDL.xml에 패킷 구조를 정의해두고 파싱할 예정 (Packet Definition List) 자동화 코드를 만들 때 1) 하드코딩 2) 재사용 할 수 있는 부분 찾기 3) 자동화하기 코드 PacketGenerator PDL.xml PacketFormat.cs Program.cs
설명 PDL.xml에서 한줄씩 가져와서 줄 부터 작업을 하는데 두번째 줄을 가져오면 memberType은 long이 될 것이고, 그에 따라 PacketFormat에서 정의한 포맷대로 {숫자}에 인자로 전달해준 변수들을 집어넣어 하나의 문자열로 만들고 각 ~Code string 변수에 넣어 코드를 대신 작성해주는 코드이다. "public long play...
코드 PacketFormat.cs Program
설명 프로그램 실행할 때 인자로 넘겨주는 게 있으면 pdlPath로 설정 GenPackets.bat 를 만들어서 PacketGenerator.exe를 대신 실행해주면서 인자를 전달해주는 역할을 해준다. XCOPY /Y : 같은 이름이 있으면 덮어쓴다는 옵션 Packe
총 정리
설명 Server의 Main에서 Listener를 Init할때 ClientSession 객체를 바로 생성해주는 것이 아닌, SessionManager를 통해 Generate해서 모든 세션을 관리하는 방식을 채택했다. 세션마다 고유 번호를 할당하고 id를 키값으로 Dictionary에 ClientSession을 넣어서 생성, 찾기, 삭제를 할 때마다 lock...
설명 이전까지는 클라이언트 세션을 연결되자마자 바로 GameRoom의 List에 넣어주고 있었지만, 이번에는 JobQueue 개념을 이용해 Queue에 일단 GameRoom의 List에 넣어주는 작업을 '예약'해주고 있다. 코드 ServerCore JobQueue.cs Server GameRoom.cs ClientSession.cs PacketHan...
설명 JobTimer라는 중앙시스템을 하나 만들어두고, job들을 일정시간 후에 실행시키도록 관리를 맡기는 식으로 짜는게 효율적이고 Main이 커지는 것을 막을 수 있다. 우선순위 큐를 구현하고 job마다 설정된 시간 순서대로 logn의 시간복잡도 안에 정렬시킨 후 빠르게 때가 된 job들을 실행시키는 방식으로 구현해보자 Server의 Main에서 Fl...
설명 유니티에서는 백그라운드에서 유니티 게임오브젝트 접근하거나 하면 크래시가 나는 경우가 있다. 그래서 메인쓰레드에서만 접근하도록 한다. ServerCore dll을 곧바로 유니티로 이식하면 디버깅하는데 어려움이 있다. 처음에는 코드를 수동으로 옮기도록 했다. 유니티에서 Span, TryWriteBytes, slice와 같은 것들은 사용할 수 없어서 코...
강의 주제 로그만 찍고 땡이 아니라 추가적인 액션(플레이어를 찾아 움직이게 하거나 스킬을 쓰도록)을 하도록 해보자 내용 문제1 PacketHandler에서 로그가 찍히지 않는 이유 유니티는 자신이 지정한 쓰레드가 아니라 다른 쓰레드에서 게임과 관련된 부분에 접근하는 것을 원천 차단한다. 따라서 패킷을 만들면 바로 핸들러를 통해 바로 처리하는게 아니라...
설명 xml 정의 S_BroadcastEnterGame 서버측에서 해당 플레이어가 들어오면 주변 모든 플레이어들에게 전송할 목적인 패킷 C_LeaveGame 해당 플레이어가 떠날때 클라이언트 쪽에서 떠남을 알리는 패킷 S_BroadcastLeaveGame 어떤 유저가 떠났는지 주변 유저들에게 뿌리는 목적인 패킷 S_PlayerList 해당 유저에게...
마지막