跨线程的套接字锁定
本文关键字:锁定 套接字 线程 | 更新日期: 2023-09-27 17:57:55
在我的ReceiveCallBack中,用异步套接字锁定()那里的套接字是个好主意吗?我这么问是因为可能另一个线程同时在套接字上发送数据。
private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
lock(client)
{
int bytesRead = client.EndReceive(ar);
// do some work
// Kick off socket to receive async again.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
}
// This is commonly called by another thread
public void SendMessage(string cmdName, Object data)
{
lock (client)
{
client.Send(arrayofdata, 0, arraylength, 0);
}
}
如果你想让它线程安全并能够同时发送和接收,你需要创建两个锁同步对象:
private readonly object sendSyncRoot = new object();
private readonly object receiveSyncRoot = new object();
private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
lock (receiveSyncRoot)
{
int bytesRead = client.EndReceive(ar);
// do some work
// Kick off socket to receive async again.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
}
// This is commonly called by another thread
public void SendMessage(string cmdName, Object data)
{
lock (sendSyncRoot)
client.Send(arrayofdata, 0, arraylength, 0);
}
通常,最好使用专用的syncRoot
对象,而不是锁定其他类或成员。这样可以避免微妙的死锁。
否。不要那样做。处理套接字的最佳方法是封装。除了声明它的类之外,不要将它公开给任何东西。这样做可以很容易地确保一次只有一个接收挂起。无需使用锁。
至于发送。这样做:
public class MyClient
{
private readonly Queue<byte[]> _sendBuffers = new Queue<byte[]>();
private bool _sending;
private Socket _socket;
public void Send(string cmdName, object data)
{
lock (_sendBuffers)
{
_sendBuffers.Enqueue(serializedCommand);
if (_sending)
return;
_sending = true;
ThreadPool.QueueUserWorkItem(SendFirstBuffer);
}
}
private void SendFirstBuffer(object state)
{
while (true)
{
byte[] buffer;
lock (_sendBuffers)
{
if (_sendBuffers.Count == 0)
{
_sending = false;
return;
}
buffer = _sendBuffers.Dequeue();
}
_socket.Send(buffer);
}
}
}
这种方法不会阻止任何调用方,所有发送请求都会依次处理。