C# 具有工作线程的WCF服务?
我正在尝试编写一个WCF服务,它将驻留在Windows服务中。此WCF服务将只向列表中添加字符串,然后工作线程将定期处理此列表。实现这一目标的最佳方式是什么?我读过一些相互矛盾的例子,这些例子让我感到困惑。服务和线程共享列表对象的最佳方式是什么 更新: 谢谢你到目前为止的回复。我只是想澄清一下,我不是在为列表的同步或如何使其线程安全而挣扎。所有这些都和我在C++中使用的原理一样。我正在努力解决的是在哪里定义这个列表,以便可以从WCF服务和工作线程访问它。在C++中,我会在全局范围内创建列表,但C语言没有全局范围。如果我在WCF服务类中定义它,线程将看不到它。如果我在服务类(定义并启动线程函数的地方)中定义它,WCF服务将无法看到它。我相信不久前我在ATL做过类似的事情,但现在是周五下午,灰色细胞已经放弃了这一天 更新2: 我应该在哪里定义工作线程?在Windows服务类(即主机)或WCF服务中?WCF服务应该是具有列表成员和线程函数的单例服务吗?这就解决了访问问题。在完成了大量的COM之后,我认为WCF服务是一个COM组件,实例在被访问后就会消亡。这让我想把静态列表和线程函数放在Windows服务类中。对于它来说,这仍然是一个更自然的地方,但也许我只是没有用.NET的方式思考。1)创建Windows服务 2) WS()中的主机WCF 3) 进行线程同步()C# 具有工作线程的WCF服务?,c#,.net,multithreading,wcf,C#,.net,Multithreading,Wcf,我正在尝试编写一个WCF服务,它将驻留在Windows服务中。此WCF服务将只向列表中添加字符串,然后工作线程将定期处理此列表。实现这一目标的最佳方式是什么?我读过一些相互矛盾的例子,这些例子让我感到困惑。服务和线程共享列表对象的最佳方式是什么 更新: 谢谢你到目前为止的回复。我只是想澄清一下,我不是在为列表的同步或如何使其线程安全而挣扎。所有这些都和我在C++中使用的原理一样。我正在努力解决的是在哪里定义这个列表,以便可以从WCF服务和工作线程访问它。在C++中,我会在全局范围内创建列表,但C
4) 利润 一般模式是在服务启动时启动服务主机。一旦启动,就可以创建工作线程。工作线程和服务调用将需要访问需要同步的共享数据结构。在共享数据对象上设置服务存款项,并发出运行工作线程的信号。工作进程完成后,重置等待句柄的状态 这里有一个快速的小shell,它使用.NET4中的并发集合(在这个例子中,我还使用了.NET4中的任务并行库)。您的问题陈述似乎是不同线程或进程上的典型生产者/消费者,因此这应该让您对如何构建事物有一个合理的想法:
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();
}
}
}
命名空间ConcurrentCollectionTest
{
使用制度;
使用System.Collections.Concurrent;
使用System.Threading.Tasks;
内部静态类程序
{
私有静态void Main(字符串[]args)
{
ConcurrentQueue cq=新ConcurrentQueue();
BlockingCollection bc=新BlockingCollection(cq);
bool moreItemsToAdd=true;
//消费线程
Task.Factory.StartNew(()=>
{
而(!bc.已完成)
{
字符串s=bc.Take();
控制台。写入线(s);
}
});
//生产者线程
Task.Factory.StartNew(()=>
{
int i=1;
while(moreItemsToAdd)
{
添加(“字符串”+i++);
}
完成添加();
});
//主线
Console.ReadLine();
moreItemsToAdd=false;
Console.ReadLine();
}
}
}
我认为您具体要求的是,如何将集合实例的引用传递到WCF服务实例中。问题的关键在于:通常情况下,ServiceHost代码将根据服务的InstanceContextMode设置(默认值为PerSession)启动WCF服务实例。这意味着它将根据需要为每个客户端会话启动一个实例。由于主机代码无法直接访问这些自动创建的实例,因此无法注入共享集合
一种解决方案是让您的主机提供一个WCF服务实例,该实例通过构造函数参数或属性设置器添加共享集合。ServiceHost有一个构造函数接受这个实例,但它有一个主要的折衷。这种方法意味着您正在创建一个单例WCF服务(),因此可伸缩性将受到影响。通过设置为multiple,您可以在某种程度上缓解这种情况,但您还必须编写WCF服务代码来处理资源的内部同步
。在C++中,我将在全局范围内创建列表,但C ^没有全局范围。
任何公共静态成员都是全局可见的。当然,您必须实现自己的同步。您可以在WCF服务的静态构造函数中启动工作线程。当然,不管是
并发模式
还是InstanceContextMode
,只有一个工作线程。如果这是您想要的,那么下面的代码可能适合您
[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);
}
}
[服务合同]
公共接口服务
{
[经营合同]
无效队列字符串值(字符串值);
}
[服务行为(…)]
公共类YourService:IYourService
{
私有静态BlockingCollection s_队列=新建BlockingCollection();
静态服务()
{
var线程=新线程(
() =>
{
while(true)
{
字符串值=s_Queue.Take();
//在这里处理字符串。
}
});
thread.IsBackground=true;
thread.Start();
}
公共无效队列字符串值(字符串值)
{
添加(值);
}
}
我已经使用生产者-消费者模式来实现工作线程逻辑。BlockingCollection
类为实现tha提供了一种简单的机制