【问题标题】:Threaded Socket.Send()线程 Socket.Send()
【发布时间】:2013-12-16 15:21:07
【问题描述】:

我有 2 个线程同时运行,每个线程都在写入 socket.Send() 流,

   While (soc.Connected)
        {


                byte[] byData = new byte[2];
                byData = System.Text.Encoding.ASCII.GetBytes("A");
                soc.Send(BitConverter.GetBytes(byData.Length));
                soc.Send(byData);


        }

另一个线程使用完全相同的代码,只是它发送的是“1”而不是“A”。

另一端的数据会是什么样子?它会是 AAAAAAA 或 111111111 的流,还是像 A1A1111AAAA1 那样随机混合?

我是否应该完全避免这种发送方式并阻止发送直到另一个线程完成?

【问题讨论】:

  • 你喜欢思考这样的事情吗?不?然后避免出现必须提出此类问题的情况。
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 大声笑尝试预测代码行为有什么问题?这是一个合理的问题,我有一个多线程应用程序,每个线程可能有一些数据要发送。如果他们在没有锁的情况下的行为是一致的并且以 AAAAAAAAA11111111111 或 11111111AAAAAA 结尾,我就不必实施锁。
  • Socket.Send() 不是线程安全的,因此没有可预测的行为,您可能会收到 AAAAAAA 或 111111111,或者您可能会收到 A1A1111AAAA1 或者您可能会遇到导致程序崩溃的异常。跨度>
  • 非常感谢,正是我正在寻找的答案。直到现在我才知道线程安全是什么意思。所以这意味着我必须锁定发送发生的代码。

标签: c# multithreading sockets


【解决方案1】:

我是否应该完全避免这种发送方式并阻止发送直到另一个线程完成?

是也不是,您应该完全避免这种情况,但没有必要在其他线程完成之前阻止发送。

你可以做的是有一个负责发送数据的第三个线程,你的两个需要发送数据的线程将他们的数据放到线程安全队列中。然后发送线程会将要完成的工作出列并通过网络发送出去。

const int MAX_QUEUE_LENGTH = 10;
private BlockingCollection<MyMessageContainer> messageQueue = new BlockingCollection<MyMessageContainer>(new ConcurrentQueue<MyMessageContainer>(), MAX_QUEUE_LENGTH);

void ProcessMessages()
{
    foreach (var message in messageQueue.GetConsumingEnumerable())
    {
        if(soc.Connected == false)
            break;

        soc.Send(message.ToPaylod());
    }
}

void GenerateMessageOne()
{
    while(true)
    {
        messageQueue.Add(new MyMessageContainer("A"));
    }
}

void GenerateMessageTwo()
{
    while(true)
    {
        messageQueue.Add(new MyMessageContainer("1"));
    }
}


class MyMessageContainer
{
     public MyMessageContainer(string message)
     {
          _message = message;
     }

     private string _message;

     public byte[] ToPayload()
     {
         var lengthBytes = BitConverter.GetBytes(byData.Length);
         return lengthBytes.Concat(() => System.Text.Encoding.ASCII.GetBytes(_message)).ToArray();
     }
}

上面的代码将让两个线程同时排队工作而不会阻塞,直到队列达到MAX_QUEUE_LENGTH的长度,一旦在那里调用messageQueue.Add(现在将开始阻塞,直到发送线程有机会清理一些房间,一旦房间被创造出来,它会解锁其中一个功能并让它继续。

【讨论】:

  • 这正是我会做的,+1。
【解决方案2】:

如果您想要随机排序的输出,最简单的解决方案是简单地在实际写入套接字的行周围加一个锁。为了公平起见,我还建议添加对 Thread.Sleep 的调用,尽管这在某种程度上是可选的。

While (soc.Connected)
{
    byte[] byData = new byte[2];
    byData = System.Text.Encoding.ASCII.GetBytes("A");
    lock(soc) 
    {
        soc.Send(BitConverter.GetBytes(byData.Length));
        soc.Send(byData);
    }
    Thread.Sleep(0);
}

【讨论】:

    猜你喜欢
    • 2012-07-14
    • 2013-05-12
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    相关资源
    最近更新 更多