말 그대로, 유니티와 웹소켓을 이용한 개발을 하던 도중 코루틴을 실행시킬 수 없는 문제에 빠졌었다. 누가 유니티를 웹소켓을 같이 쓰겠냐 싶긴 하지만, 비슷한 문제에서도 적용할 수 있을거라 생각되어 적어보게 되었다.
스레드의 개념, 그리고 스레드를 이용할 때 주의해야 하는 점 등을 알고 있으면 좋습니다. 모르면 이제부터 알면 되죠.
콜백 메소드(call-back)
에 대해 알고 있으면 좋습니다. 모르시는 분들은 간단하게, 메소드를 메소드의 인자로 넘긴 것 정도라고 생각하시면 됩니다.
플레이어의 위치를 동기화하기 위해 웹소켓 서버에 접속 된 후 부터 0.1초마다 자신의 위치를 서버로 보내기로 했다.
이를 위해, 서버에 접속하는 메소드에 성공 후 실행되는 콜백으로 1번에서 언급한 작업을 하는 코루틴을 실행시키도록 넘겨주었다.
서버에는 연결이 됐지만, 위치를 0.1초마다 보내는 코루틴은 전혀 실행되지 않았다?
라는 것이 오늘의 문제 내용이다. 하다못해 코루틴이 실행된 뒤 찍히는 로그조차도 찍히지 않는데다 에러도 뱉는 내용이 아무것도 없어 큰 벽에 가로막힌 기분이었다.
socketManager.AddOpenEvent((sender, e) =>
{
print("Established!");
StartCoroutine(SendPositionInfinitely());
});
소켓 매니저 어쩌구는 여러분은 모르셔도 됩니다. 결론만 따지자면, 서버에 접속 됐을 때 저 코루틴을 실행시키기로 했다. 이 부분만 이해하시면 됩니다.
코루틴 내용은 다음과 같습니다.
private IEnumerator SendPositionInfinitely()
{
Debug.Log("Start coroutine");
while (true)
{
SendPositionPacket();
yield return new WaitForSeconds(.1f);
}
yield return null;
}
SendPositionPacket()
메소드는 그냥, 서버에 자기 위치 담은 패킷 보내는거니까 신경 안쓰셔도 됩니다.
결론적으로는 저런식으로 로그를 한번 찍고 매번 저 코루틴을 통해서 위치를 보내기로 했었어요.
근데? 로그도 안찍히고 패킷도 안가고 아무튼 참 착잡했다는거지... 에러가 뜨는것도 아니고. 진짜 이거 이랬을때는 정신 나갈 것 같더라고요. 한시간동안 패닉에 빠져있었음.
결론부터 이야기하자면, WebSocket
에서 돌아가는 작업들은 전부 비동기 작업이고, 해당 작업마다 스레드를 따로 파서 작업이 돌아가고 있던겁니다. 이제부터 이 글에서는 얘를 웹소켓 스레드
라고 부르겠습니다.
그리고, 유니티의 코루틴은 유니티의 메인 스레드
에서 돌아가야 합니다. 라고 스택오버플로우가 가르쳐주더라고요.
그 글을 읽고나니 비동기 작업이라서 유니티 메인 스레드 대신 웹소켓 스레드에서 코루틴이 실행돼서 안됐던거구나! 싶은 생각이 들었습니다.
그래서 코드를 다음과 같이 고쳤습니다.
private bool established;
socketManager.AddOpenEvent((sender, e) =>
{
print("Established!");
established = true;
//StartCoroutine(SendPositionInfinitely());
});
이런식으로, 연결이 됐을 때 established
라는 이름의 플래그를 메인 스레드에서 켜주기로 했습니다. 이런 다음 SendPositionInfinitely()
의 내용을 다음과 같이 바꿨습니다.
private IEnumerator SendPositionInfinitely()
{
while (!established) yield return null;
Debug.Log("Start coroutine");
while (true)
{
SendPositionPacket();
yield return new WaitForSeconds(.1f);
}
yield return null;
}
established
가 true
가 되기 전까지는 계속 루프를 돌고, true가 된 시점부터는 0.1초에 한번씩 패킷을 보내기로 했습니다.
이런 방식으로 고치면, 웹소켓 스레드에서 코루틴이 실행되던걸 메인 스레드에서 실행되는 식으로 바꾸게 되고, 그로 인해 thread-safe
하게 코루틴을 실행시켜줄 수 있었습니다.
결국 이렇게 한 뒤부터는 잘 돌아가더라고요.
오늘의 결론!
Unity
의 Coroutine
은 유니티 메인 스레드에서만 돌아가야 실행된다.bool
형식의 플래그
를 이용하는 방식으로 thread-safe
한 상태로 작업을 해줄 수 있다.WebSocket
과 관련이 있는건 아니다!메인스레드에서 돌려야 한다는 사실을 몰라서 대충 30분~1시간 정도를 왜 안되지? 하면서 엎드려 있었습니다. 힘들더라고요. 유니티 포럼은 무적이고 스택오버플로우는 신이다...
고등학생 게이ㅁ 개발자 김선민이었습니다. 감사합니다.