궁금한 점이 있습니다.
분석해 보았을 때 우려하신 문제가 발생하려면 꽤 까다로운 조건을 충족해야 합니다.문제 상황 1(보낼 SendBuffer가 없는데 WSASend()를 호출)1. Send가 걸린 상황2. Thread A : Lock을 걸어 sendQueue에 데이터를 삽입 후 Lock을 품(Send).3. Thread B : 완료 루틴에 의해 깨어나 sendQueue에 데이터가 있는지 확인하고 RegisterSend 호출(ProcessSend).4. Thread B : sendQueue에 예약된 데이터를 전송(RegisterSend).5. Thread C : 전송 결과를 완료 루틴으로 받고 sendRegistered 플래그를 품(ProcessSend).6. Thread A : 이어서 sendRegistered 플래그를 확인하고 RegisterSend 호출(Send).7. Thread A : sendQueue를 확인했으나 SendBuffer가 없는 상황이 발생(RegisterSend).8. Thread A : 보낼 SendBuffer가 없는데 전송을 시도하니 WSAEINVAL(잘못된 인자) 에러가 뜨고 실패함(RegisterSend). 이 문제 상황 1을 더 깊게 파고 들면 다음의 연장선에 위치한 문제를 파악할 수 있습니다.문제 상황 2(데이터를 넣었는데 보내지 않는 상황)1. Send가 걸린 상황2. Thread A : Lock을 걸어 sendQueue에 데이터를 삽입 후 Lock을 품(Send).3. Thread B : 완료 루틴에 의해 깨어나 sendQueue에 데이터가 있는지 확인하고 RegisterSend 호출(ProcessSend).4. Thread B : sendQueue에 예약된 데이터를 전송(RegisterSend).5. Thread C : 전송 결과를 완료 루틴으로 받고 sendRegistered 플래그를 품(ProcessSend).6. Thread A : 이어서 sendRegistered 플래그를 확인하고 RegisterSend 호출(Send).7. Thread A : sendQueue를 확인했으나 SendBuffer가 없는 상황이 발생(RegisterSend).8. Thread A : 보낼 SendBuffer가 없는데 전송을 시도하니 에러가 뜨고 실패함(RegisterSend).int32 errCode = ::WSAGetLastError(); if (WSA_IO_PENDING != errCode) { HandleError(errCode); _sendEvent.owner = nullptr; _sendEvent.sendBuffers.clear(); // 9. Thread D : Lock을 걸어 sendQueue에 데이터를 삽입 후 Lock을 품(Send).10. Thread D : sendRegistered 플래그를 확인했는데 누군가 점유 중인 상태이니 RegisterSend를 호출하지 않음(Send).11. Thread A : sendRegistered 플래그를 false로 바꿈(RegisterSend).12. Thread D에서 넣은 SendBuffer를 처리하지 못 하는 상황이 발생.정확히 말해선 7번 과정에서 sendQueue에 있는 내용을 전부 빼오고 Lock을 푸는 그 시점부터 WSASend() 호출 후 에러가 발생해 sendRegistered를 false로 바꾸기 이전의 모든 구간에서 문제 상황 2가 발생할 수 있습니다.애초에 WRITE_LOCK을 걸고 sendQueue에 변화를 주는 로직과 sendRegistered의 상태를 전이하는 로직이 분리되어서 생기는 문제이기에 다음과 같이 Lock을 건다고 해서 해결되지 않습니다.sendQueue는 이미 변화되었고 이를 탐지하지 못 했기에 발생한 문제이니까요.int32 errCode = ::WSAGetLastError(); if (WSA_IO_PENDING != errCode) { HandleError(errCode); _sendEvent.owner = nullptr; _sendEvent.sendBuffers.clear(); WRITE_LOCK; _sendRegistered.store(false); }ProcessSend()의 문제가 아니라 여러 스레드를 통해 Send() -> RegisterSend()를 하는 과정에서 발생하는 문제입니다.그리고 그 과정에서 문제 상황 1이 먼저 선행되어 에러가 발생할 수 있는 조건이 충족되어야 합니다.