해결된 질문
작성
·
233
1
안녕하세요, 이전 질문 글에 비슷한 내용의 질문이 있었는데 조금 다른 부분이 궁금해서 질문글을 올립니다.
1. Send를 할 때 lock을 건다. (현재 _pendingList가 비어있으면, RegisterSend() 호출하고 이게 끝나야 lock이 풀리게된다. )
2. RegisterSend에서는 SendAsync를 호출하는데 true라면, 1에서 잡은 lock은 바로 풀릴것이다. 그런데 만약 false가 되면 3으로 넘어간다.
3. OnSendCompleted 에서 lock을 걸려고 한다. 👉 이 때 2번에서 SendAsync가 false가 되어 3으로 넘어온 경우라면, 1에서 잡은 lock이 아직 안풀렸을 것 같은 데 잡을 수 있나?
3번의 질문 내용이 궁금합니다. (1번에서 lock을 잡은 상태로 2번을 호출했고, 2에서 SendAsync의 return 값이 false가 되어 3으로 넘어올 때가 궁금합니다.)
제가 비동기 프로그래밍이 익숙하지 않다보니 이해가 부족해서 이런 질문을 올리게 되었습니다.😁
(제가 아직 뒷쪽 강의를 다 듣지 않았는데, 뒤 쪽에 혹시 이런 설명이 나올까요..?)
감사합니다(__)
public void Send(byte[] sendBuff)
{
lock(_lock)
{
_sendQueue.Enqueue(sendBuff);
if (_pendingList.Count == 0) // 대기중인게 하나도 없으니 해라.
RegisterSend();
}
}
void RegisterSend()
{ // _pendingList가 비어있을 때만 여기로 들어온다.
//_pendingList.Clear();
//_sendArgs.SetBuffer(buff, 0, buff.Length);
while(_sendQueue.Count > 0)
{
byte[] buff = _sendQueue.Dequeue();
_pendingList.Add(new ArraySegment<byte>(buff, 0, buff.Length));
}
_sendArgs.BufferList = _pendingList;
bool pending = _socket.SendAsync(_sendArgs);
if (pending == false)
{
OnSendCompleted(null, _sendArgs);
}
}
void OnSendCompleted(object sender, SocketAsyncEventArgs args)
{ // 예약한 pendingList 완료됨
lock(_lock)
{
if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
{
try
{
_sendArgs.BufferList = null;
_pendingList.Clear();
if(_sendQueue.Count > 0) // 보내는동안 누가 또 Queue에 쌓았다.
{
RegisterSend();
}
}
catch (Exception e)
{
Console.WriteLine($"OnSendCompleted Fail {e}");
}
}
else
{
Disconnect();
}
}
}
답변 1
0
Lock 종류에 따라서 Recursive Lock을 지원하는 경우가 있고 아닌 경우가 있습니다.
여기서 반복적(Recursive)이라 함은,
말 그대로 특정 쓰레드가 이미 Lock을 잡고 있는 상태에서
동일한 Lock을 반복해서 잡을 수 있느냐~ 인데요.
C#에서 lock (~~)을 해서 잡는 경우는 허락되기에
위 코드에 아무런 문제가 없습니다.
참고로 C++의 std::mutex는 반복해서 잡을 수 없는 등
사용하는 동기화 객체에 따라 조금씩 차이가 있으니 이 부분은 확인해야 합니다.
다만 컨텐츠 작업자 입장에서 어지간해서 반복해서 잡을 수 있는 락을 사용하는게 편리합니다.
제가 문의 한 케이스는 1->2->3 순서대로 한 thread가 실행중이고,
C#에서는 동일 thread에서 lock(~) 을 이용하는 것에 대해서는 recursive lock을 허용하기 때문에 문제되지 않는 것이군요.
친절한 설명 감사드립니다.🙏