【发布时间】:2014-06-17 13:25:02
【问题描述】:
我正在编写一项服务,该服务将不断受到来自不同来源的影响。该服务需要在对单个共享资源的某些调用期间保留数据。在这种情况下是一个 XML 文件(我知道这是存储数据的愚蠢选择,但我无法控制该决定)。
所以我希望服务在其中运行
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
因为除了这种情况,我不需要会话,而且我的对象构造函数中的设置代码很少。但是,静态变量不会在服务的每次调用之间共享(它们来得又快又猛)。所以对文件的静态锁定不起作用。我很难学到这一点:
private string _dataFile;
private static object _lock = new object();
private MusicData Get(string fileName)
{
lock (_lock)
{
using (var stream = File.OpenRead(fileName))
{
var serializer = new XmlSerializer(typeof(MusicData));
return serializer.Deserialize(stream) as MusicData;
}
}
}
private void Put(string fileName, MusicData data)
{
lock (_lock)
{
XmlSerializer x = new XmlSerializer(typeof(MusicData));
using (TextWriter writer = new StreamWriter(fileName))
{
x.Serialize(writer, data);
}
}
}
在这个地方最好的策略是什么?我不想仅仅为此将我的InstanceContextMode 更改为PerSession,任何类型的数据库解决方案都是不可能的。上面的代码导致了可怕的错误:
该进程无法访问该文件,因为它正被另一个进程使用
【问题讨论】:
-
所以也许改用
InstanceContextMode.Single?还有ConcurrencyMode.Single。这会将服务实例切换到单例模式,即轮流处理传入请求的队列。那时你甚至不需要锁。 -
感谢您的想法,但我的服务需要扩展,并且会有很多请求进入,因此对每个请求进行排队并不理想。我宁愿只排队访问文件并让所有其他操作并行运行。
-
静态变量在同一个AppDomain中的实例之间共享,这就是.NET的工作方式; WCF 无法改变这一点。你一定有其他问题。您是否有任何机会托管在 IIS 上?有多个 AppDomain/进程?此外,
_lock未标记为readonly。有没有可能被重新分配到某个地方? -
使用锁的替代方法是将MaxConcurrentInstances 设置为1。
-
嘿@Eli _lock 没有在其他任何地方引用。我写了一个集成测试,它使用: Parallel.For(0, 1000, MyFunc);在 MyFunc 中,我创建了一个新的服务实例并写入文件。
标签: c# multithreading wcf synchronization locking