C#Threading在Window服务创建问题

时间:2012-07-26 05:19:08

标签: c# multithreading windows-services

我遇到电子邮件发送窗口服务的问题。服务在每三分钟延迟后启动,并获取要从数据库发送的消息,然后开始发送它。代码如下所示:

        MessageFilesHandler MFHObj = new MessageFilesHandler();
        List<Broadcostmsg> imidiateMsgs = Manager.GetImidiateBroadCastMsgs(conString);
        if (imidiateMsgs.Count > 0)
        {

           // WriteToFileImi(strLog);

            Thread imMsgThread = new Thread(new             ParameterizedThreadStart(MFHObj.SendImidiatBroadcast));              
            imMsgThread.IsBackground = true;
            imMsgThread.Start(imidiateMsgs);
        }

这会将消息发送到大型列表,并需要很长时间才能完成发送到更大的列表。现在问题发生在消息仍在发送并且服务获取要发送的新消息时,先前的发送被挂起并且新消息发送开始,虽然我使用线程,每次服务获取消息发送它都会启动新线程。 你可以帮助我在代码中犯错误的地方。

2 个答案:

答案 0 :(得分:0)

看起来要求是构建一个消费者生产者队列。在哪个生产者将继续向列表添加消息,消费者将从该列表中选择项目并使用它进行一些工作 我唯一担心的是,您每次创建一个新线程来发送电子邮件而不是从线程池中挑选线程。如果继续创建越来越多的线程,由于上下文切换产生的开销,应用程序的性能将下降。

如果您正在使用.Net framwe work 4.0,那么灵魂变得非常容易。您可以使用System.Collections.Concurrent.ConcurrentQueue来对项目进行排队和出列。它的线程安全,因此不需要锁定对象。使用Tasks处理您的邮件。

BlockingCollection在其构造函数中采用IProducerConsumerCollection,或者如果调用其空构造函数,它将默认使用ConcurrentQueue。

所以要将你的信息排入队列。

//define a blocking collectiom
var blockingCollection = new BlockingCollection<string>();

//Producer
Task.Factory.StartNew(() =>
{
    while (true)
    {
        blockingCollection.Add("value" + count);
        count++;                    
    }
});

//consumer
//GetConsumingEnumerable would wait until it find some item for work
// its similar to while(true) loop that we put inside consumer queue
Task.Factory.StartNew(() =>
{
    foreach (string value in blockingCollection.GetConsumingEnumerable())
    {
        Console.WriteLine("Worker 1: " + value);
    }                
});

<强>更新

因为您使用的是FrameWork 3.5。我建议你看一下Joseph Albahari对Consumer/Producer Queue的实现。它是你能找到的最好的之一。

直接从上面的链接中获取代码

public class PCQueue
{
  readonly object _locker = new object();
  Thread[] _workers;
  Queue<Action> _itemQ = new Queue<Action>();

  public PCQueue (int workerCount)
  {
    _workers = new Thread [workerCount];

    // Create and start a separate thread for each worker
    for (int i = 0; i < workerCount; i++)
      (_workers [i] = new Thread (Consume)).Start();
  }

  public void Shutdown (bool waitForWorkers)
  {
    // Enqueue one null item per worker to make each exit.
    foreach (Thread worker in _workers)
      EnqueueItem (null);

    // Wait for workers to finish
    if (waitForWorkers)
      foreach (Thread worker in _workers)
        worker.Join();
  }

  public void EnqueueItem (Action item)
  {
    lock (_locker)
    {
      _itemQ.Enqueue (item);           // We must pulse because we're
      Monitor.Pulse (_locker);         // changing a blocking condition.
    }
  }

  void Consume()
  {
    while (true)                        // Keep consuming until
    {                                   // told otherwise.
      Action item;
      lock (_locker)
      {
        while (_itemQ.Count == 0) Monitor.Wait (_locker);
        item = _itemQ.Dequeue();
      }
      if (item == null) return;         // This signals our exit.
      item();                           // Execute item.
    }
  }
}

此方法的优点是您可以控制为优化性能而创建的线程数。使用线程池方法,虽然它是安全的,但您无法控制可以同时创建的线程数。

答案 1 :(得分:0)

我认为你在一个循环中使用你的代码 WAITS 用于新消息,你管理那些等待吗?让我们看看:

while(imidiateMsgs.Count == 0)
{
    //Wait for new Message
}

//Now you have a new message Here

//Make a new thread to process message

等待有不同的方法,我建议使用BlockingQueues:

在公共区域:

BlockingCollection<Broadcostmsg> imidiateMsgs = new BlockingCollection<Broadcostmsg>();

在您的消费者(生成消息的线程)中:

SendImidiatBroadcast = imidiateMsgs.Take();//this will wait for new message
//Now you have a new message Here

//Make a new thread to process message

在生产者(回复消息的线程)中:

imidiateMsgs.Add(SendImidiatBroadcast);

每次都必须使用线程池创建新线程来回复消息,每次都要初始化新线程。