👍 조성개발실록
라이트모드
🏷️
태그
📝
방명록

👥 C++ 멀티스레딩 맛 한번 보세요

CPP

January 03, 2024


🍔

저번학기에 게임 만드는 팀플이 있었는데요
처음에는 C로 시작했고 나중에 C++로 확장했지만
사실 사용중인 이미지 렌더링 라이브러리가 C로 작성된거기도 하고 해서
아무튼 시작은 C였고 멀티스레딩은 생각을 해두지 않았었습니다
그럼 이제 문제가 뭐냐 모든 동작이 순차적이라는 것인데요

예를 들어 가장 문제점은
게임에서는 땅을 파는 함수가 있는데
이 함수에서는 진동 모션과 블록의 파괴 등까지 해서 한 동작에 렌더링이 최소 5번 일어납니다

아래의 진동 모션이야말로 주범인데
앞뒤로 왔다갔다를 보여줘야 하니 렌더링이 다다닥 있습니다
맥북을 쓰는 팀원분은 렌더링이 빨라서 체감이 크지 않는데
제 윈트북은 개느려서 이 렌더링 세 번에 걸리는 시간이 상당히 크고 그동안 다른 동작에 도달하지 못하니 NPC들은 멈춰있고 그렇습니다

그래서 어케함??

그래서 이 땅 파는 함수 dig을 다른 스레드에서 실행하고자 했습니다
먼저 그러려면 #include <thread>로 스레드 헤더를 가져옵니다
이제 스레드 객체를 thread myThread(함수포인터, 객체, 인자, 인자, ... )와 같이 생성해줍니다.
예를 들어, 제 경우 pc.dig(x, y);에 대한 스레드 객체를 생성하기 위해
thread digThread(&PC::dig, &pc, x, y); 이렇게 작성했습니다

이제 두 가지 선택지가 있는데

  • myThread.join() : 메인스레드는 저거 끝나기를 기다림
  • myThread.detach() : 메인스레드와 분리시켜 백그라운드 작업을 시키고, 메인스레드는 할 일 하러 간다

메인스레드는 계속 일하고 dig만 따로 실행하면 좋겠으니, detach합니다

주의..

해야 할 점이 있었는데 switchcase문 내에서 thread 변수를 만드니까 thread 초기화가 case레이블에 의해 생략되었습니다. 뭐 이런 에러가 발생합니다
case문 내부에서 변수를 선언한게 문제인데,

  • switch시작 전에 변수 선언하거나

  • case문을 중괄호 {}로 묶거나 둘 중 하나 선택해서 해결할 수 있습니다

    대신 후자의 방식은 당연히 scope가 중괄호 내부로 제한되니 그 안에서만 사용할 수 있습니다

동기화

그리고 이제 연산이 일부 병렬적이므로 자원에 동시에 접근하고 수정하게 될 수도 있습니다..
따라서 동기화하려면
여러 방법이 있는 것 같은데 저는 std::mutex를 쓰는 방법을 택했습니다

#include <mutex>로 먼저 뮤텍스를 가져오신 다음에
전역에 std::mutex m과 같이 뮤텍스를 하나 생성해줍니다
이제 동기화하려는 코드 앞뒤로 m.lock(), m.unlock()을 써서 감싸줍니다
대충 이런 식

그럼 짜잔

..

..

..

..

딱히 보여줄 자료는 없고요.. 확실히 효과있었습니다

처음부터 멀티스레딩을 염두에 두고 개발했으면 좋았을걸 싶네요 아쉽습니다
전부 갈아엎을 수도 없는 노릇이라 그냥 .. 부분적으로만 스레드를 분리했었네요

이만 마칩니다.