仅在资源繁忙时才生成线程和工作队列

时间:2012-02-13 00:31:20

标签: multithreading mutex semaphore race-condition

希望有人能帮我正确设计。

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

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

到目前为止我所拥有的是(伪编码):

SendMessage(msg) {

    if(Monitor.TryEnter(wirelock,200)) {

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

     _SomeThreadSafeQueue.add(msg)

     Monitor.TryEnter(consumerlock,..

          Task.Factory.New(ConsumerThreadMethod....
    }
}


ConsumerThreadMethod() {

   lock (wirelock) {

         while(therearemessagesinthequeue)

               sendBytes...

   }

}

任何明显的竞争条件?

编辑:发现最后一个漏洞。怎么样呢?

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);
}

所以基本上使用互锁计数器作为只生成一个线程(如果需要)的方法

1 个答案:

答案 0 :(得分:0)

没有明显的比赛,但TryEnter导致一些严重的空闲时间。我实际上认为一直使用消费者线程是最好的解决方案。如果没有什么可做的,开销将非常小(如果设计不正确,消费者线程将在不工作时睡着)。

现在,您为每个已发送的消息创建一个新任务,从而导致对锁的巨大争用,因为您在使用者线程中使用了while循环。

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

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