Multithreading 仅当资源繁忙时生成线程和工作队列

Multithreading 仅当资源繁忙时生成线程和工作队列,multithreading,mutex,semaphore,race-condition,Multithreading,Mutex,Semaphore,Race Condition,希望有人能帮我正确设计这个 在我的TCP代码中,我有一个SendMessage()函数,该函数尝试写入线路。我试图设计调用,以便在发生大量并发请求时,调用移到生产者/消费者模型,但同时,如果没有并发请求,则保持单线程(以获得最大性能) 我正在努力研究如何在没有竞争条件的情况下设计它,因为无法在线程之间移动锁 到目前为止,我得到的是(伪编码): 有明显的比赛条件吗 编辑:发现上一个缺陷。这个怎么样 SendMessage(msg) { if(Monitor.TryEnter(wirelo

希望有人能帮我正确设计这个

在我的TCP代码中,我有一个SendMessage()函数,该函数尝试写入线路。我试图设计调用,以便在发生大量并发请求时,调用移到生产者/消费者模型,但同时,如果没有并发请求,则保持单线程(以获得最大性能)

我正在努力研究如何在没有竞争条件的情况下设计它,因为无法在线程之间移动锁

到目前为止,我得到的是(伪编码):

有明显的比赛条件吗

编辑:发现上一个缺陷。这个怎么样

SendMessage(msg) {

    if(Monitor.TryEnter(wirelock)) {

       try{
          sendBytes(msg);
       }
       finally {
          Monitor.Exit...
       }
   }
   else {

         _SomeThreadSafeQueue.add(msg)

        if (Interlocked.Increment(ref _threadcounter) == 1)
        {
            Task.Factory.StartNew(() => ConsumerThreadMethod());

        }
        else
        {
            Interlocked.Decrement(ref _threadcounter);

        }      
    }
}


ConsumerThreadMethod() {

     while(therearemessagesinthequeue)
           lock (wirelock) {
               sendBytes...
            }
      }

     Interlocked.Decrement(ref _threadcounter);
}

因此,基本上使用联锁计数器作为只产生一个线程的方法(如果需要)

没有明显的争用,但TryEnter会导致一些严重的空闲时间。实际上,我认为始终使用消费者线程是最好的解决方案。如果没有什么要做的,开销将非常小(如果设计正确,消费线程在不工作时将处于休眠状态)

现在,您为每个发送的消息创建一个新任务,这会导致锁上的巨大争用,因为您正在使用者线程中使用while循环

编辑:因为您使用的是非阻塞套接字,所以单个使用者线程应该足以处理所有发送请求。单个线程的吞吐量高于您的网络。如果有更多的使用者,如果不使用互斥锁序列化所有内容,就很难确保没有两个使用者线程在同一个套接字上发送。我不认为在单线程和多线程之间切换是个好主意


您当前的“多线程”解决方案不会给您带来任何性能提升,因为所有工作都使用相同的互斥锁进行保护。它将和一根线一样慢,或者说比一根线慢。

别忘了:接吻。只需使用一个线程安全队列和一个(或n,取决于最大连接数和可用核心数)专用发送方线程。与有线延迟相比,无锁队列将增加很少的延迟。实际上,我注意到我的设计中有一个缺陷。两个线程可以启动一个新线程,因为锁必须在因子之后释放。新调用,因为我不能将锁转移给使用者。我想我必须重写我的类,以允许单个线程通过所有队列(每个连接一个)嗯?否则,可能会有数百个阻塞队列(不确定线程池如何处理这些队列)您的新示例存在竞争。消费线程可以完成,但尚未递减。那么一个新任务就不会有消费者线程来处理它了。。你说得对。while()结尾和Interlocked.Decrement之间可能存在上下文切换。这很难。有什么想法吗?真的很喜欢只在突发情况下切换到消费者模型(从而允许在队列为空时释放线程)的想法,您是否建议每个连接使用一个消费者线程?或者一个主线程一个接一个地通过连接队列(在客户端没有区别,但服务器可能有1000个连接),难道每个连接都有一个线程来接收数据吗?还是使用非阻塞套接字?
SendMessage(msg) {

    if(Monitor.TryEnter(wirelock)) {

       try{
          sendBytes(msg);
       }
       finally {
          Monitor.Exit...
       }
   }
   else {

         _SomeThreadSafeQueue.add(msg)

        if (Interlocked.Increment(ref _threadcounter) == 1)
        {
            Task.Factory.StartNew(() => ConsumerThreadMethod());

        }
        else
        {
            Interlocked.Decrement(ref _threadcounter);

        }      
    }
}


ConsumerThreadMethod() {

     while(therearemessagesinthequeue)
           lock (wirelock) {
               sendBytes...
            }
      }

     Interlocked.Decrement(ref _threadcounter);
}