WCF服务与工作线程?

时间:2011-05-20 14:31:06

标签: c# .net multithreading wcf

我正在尝试编写一个驻留在Windows服务中的WCF Servce。此WCF服务只会将字符串添加到列表中,然后工作线程将定期处理此列表。实现这一目标的最佳方法是什么?我读过令人困惑的相互矛盾的例子。服务和线程共享列表对象的最佳方式是什么?

更新: 感谢到目前为止的回复。只是为了澄清,我并没有在列表的同步或如何使其线程安全方面苦苦挣扎。这一切似乎与我在C ++中习惯的原理相同。我正在努力的是在哪里定义这个列表,以便可以从WCF服务和工作线程访问它。在C ++中,我会在全局范围内创建列表,但C#没有全局范围。如果我在WCF服务类中定义它,则线程无法看到它。如果我在服务类中定义它(定义并启动了线程函数),则WCF服务无法看到它。我确信我前段时间在ATL做了类似的事情,但是周五下午,灰色的细胞已经放弃了。

UPDATE2: 我应该在哪里定义工作线程?在Windows服务类(即主机)或WCF服务中? WCF服务应该是具有列表成员和线程功能的单例服务吗?这解决了访问问题。做了很多COM后,我想把WCF服务当作一个COM组件,实例在访问后就会死掉。这使我想要将静态列表和线程函数放在Windows服务类中。这仍然是感觉更自然的地方,但也许我只是没有用.NET思考。

6 个答案:

答案 0 :(得分:3)

1)创建Windows服务

2)WS中的主机WCF(http://msdn.microsoft.com/en-us/library/ms731758.aspx

3)进行线程同步(http://www.albahari.com/threading/part2.aspx

4)利润!

答案 1 :(得分:2)

这是一个快速的小shell,它使用.NET 4中的并发集合(就此而言,我也在使用.NET 4中的任务并行库这个例子)。你的问题陈述似乎是不同线程或进程的经典生产者/消费者,所以这应该让你对如何构建事物有一个体面的想法:

namespace ConcurrentCollectionTest
{
    using System;
    using System.Collections.Concurrent;
    using System.Threading.Tasks;

    internal static class Program
    {
        private static void Main(string[] args)
        {
            ConcurrentQueue<string> cq = new ConcurrentQueue<string>();
            BlockingCollection<string> bc = new BlockingCollection<string>(cq);
            bool moreItemsToAdd = true;

            // Consumer thread
            Task.Factory.StartNew(() =>
            {
                while (!bc.IsCompleted)
                {
                    string s = bc.Take();

                    Console.WriteLine(s);
                }
            });

            // Producer thread
            Task.Factory.StartNew(() =>
            {
                int i = 1;

                while (moreItemsToAdd)
                {
                    bc.Add("string " + i++);
                }

                bc.CompleteAdding();
            });

            // Main Thread
            Console.ReadLine();
            moreItemsToAdd = false;
            Console.ReadLine();
        }
    }
}

答案 2 :(得分:1)

一般模式是在服务启动时启动服务主机。一旦启动,您就可以创建工作线程。工作线程和服务调用将需要访问需要同步的共享数据结构。将服务存放项放在共享数据对象上,并发出Wait handle信号以运行工作线程。一旦工作人员完成重置等待句柄的状态。

答案 3 :(得分:1)

我认为您要求的具体是,如何将集合实例的引用传递给WCF服务实例。以下是问题的症结所在:通常,ServiceHost代码将根据服务的InstanceContextMode设置(默认值为PerSession)启动WCF服务实例。这意味着它将根据需要为每个客户端会话启动一个实例。由于您的主机代码无法直接访问这些自动创建的实例,因此您无法注入共享集合。

一种解决方案是让您的主机提供WCF服务实例,并通过构造函数参数或属性设置器添加共享集合。 ServiceHost有一个构造函数,它接受这个实例,但它有很大的权衡。这种方法意味着您正在创建单例WCF服务(InstanceContextMode = Single),因此可伸缩性将受到影响。您可以通过将ConcurrencyMode设置为多个来缓解这种情况,但您还必须编写WCF服务代码来处理资源的内部同步。

答案 4 :(得分:1)

您可以在WCF服务的静态构造函数中启动工作线程。当然,无论ConcurrencyModeInstanceContextMode如何,都只有一个工作线程。如果这是您想要的,那么以下代码可能适合您。

[ServiceContract]
public interface IYourService
{
  [OperationContract]
  void QueueStringValue(string value);
}

[ServiceBehavior(...)]
public class YourService : IYourService
{
  private static BlockingCollection<string> s_Queue = new BlockingCollection<string>();

  static YourService()
  {
    var thread = new Thread(
      () =>
      {
        while (true)
        {
          string value = s_Queue.Take();
          // Process the string here.
        }
      });
    thread.IsBackground = true;
    thread.Start();
  }

  public void QueueStringValue(string value)
  {
    s_Queue.Add(value);
  }
}

我使用了生产者 - 消费者模式来实现工作线程逻辑。 BlockingCollection类提供了一种实现该模式的简单机制。

答案 5 :(得分:0)

  

。在C ++中,我会在全局范围内创建列表,但C#没有全局范围。

任何公共静态成员都是全局可见的。当然,你必须实现自己的同步。