C# 跨线程的套接字锁定

C# 跨线程的套接字锁定,c#,.net,multithreading,sockets,parallel-processing,C#,.net,Multithreading,Sockets,Parallel Processing,在异步套接字的ReceiveCallBack中锁定()套接字是个好主意吗?我这样问是因为有可能另一个线程同时在套接字上发送数据 private void ReceiveCallback(IAsyncResult ar) { StateObject state = (StateObject)ar.AsyncState; Socket client = state.workSocket; lock(client) { int bytesRead = client.EndReceive(ar

在异步套接字的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);
        }
    }
}
公共类MyClient
{
私有只读队列_sendBuffers=new Queue();
私人布卢发送;
专用插座(u插座),;
public void Send(字符串cmdName,对象数据)
{
锁定(发送缓冲区)
{
_sendBuffers.Enqueue(序列化命令);
如果(_发送)
返回;
_发送=真;
ThreadPool.QueueUserWorkItem(SendFirstBuffer);
}
}
私有void SendFirstBuffer(对象状态)
{
while(true)
{
字节[]缓冲区;
锁定(发送缓冲区)
{
如果(_sendBuffers.Count==0)
{
_发送=假;
返回;
}
buffer=_sendBuffers.Dequeue();
}
_socket.Send(缓冲区);
}
}
}

这种方法不会阻止任何调用者,所有发送请求都会依次处理。

最好锁定套接字本身以外的对象。我从来没有在从一个线程读取和从另一个线程写入时锁定过任何语言的套接字。它在C++,Delphi中运行良好。除了被管理之外,为什么C#不同?为什么.NET强制显式锁定非托管代码中不需要显式锁定的操作?如果两个线程都能写,那么很好,做一些锁定,但一个写一个读?@martinjames-这取决于。如果希望读写同时进行,则根本不需要锁定。但是如果你想要两次阅读或两次写作同时发生,你需要锁定。我不知道提供的代码是示例代码还是真实代码,但如果真实代码在多个发送中写入数据,则需要确保没有其他线程干扰。@Martin James-假设SendMessage方法发送文件。因此,SendMessage inside将从文件流中读取并通过套接字发送。现在假设两个线程开始发送。如果不锁定,两个文件的内容将混合在一起。是的-如果可以有多个写入程序,您需要在某个地方执行一些锁定。不止一个读者似乎没有多大意义——无法想象任何人尝试它的理由!这个问题基于一种错觉,即可以锁定对象以使代码线程安全。不能,只能阻止代码,防止它同时使用共享对象。lock语句仅使用对象存储状态。那不应该是插座。