WCF PerCall 共享资源锁定问题

Posted

技术标签:

【中文标题】WCF PerCall 共享资源锁定问题【英文标题】:WCF PerCall Shared Resource Lock Issue 【发布时间】: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 中,我创建了一个新的服务实例并写入文件。 【参考方案1】:

在您描述的场景中,共享客户端访问单个 XML 文件,您可能需要考虑 InstanceContextMode.Single 加上 ConcurrencyMode.Multiple,前提是您的服务是无状态的、线程安全的和可重入的。

使用InstanceContextMode.SingleConcurrencyMode.Multiple 的WCF 服务不应对您的方案中的任何性能问题负责。

单例服务是最终的可共享服务。当一个服务被配置为单例时,所有客户端都独立地连接到同一个已知实例,而不管它们连接到服务的哪个端点。单例服务永远存在,并且只有在主机关闭后才会被处理掉。单例在创建主机时只创建一次。

http://msdn.microsoft.com/en-us/magazine/cc163590.aspx

【讨论】:

这不会解决他观察多个锁对象的任何原因。 WCF 不会改变静态变量的性质。实例化模式在这方面没有发言权。 有趣的观点。虽然我的回答没有解决锁定行为问题,但答案似乎解决了更广泛的问题“在这个地方最好的策略是什么?”我建议他可能要考虑。看起来很合理,不违反“不想把我的InstanceContextMode改成PerSession”的条件。 ConcurrencyMode.Multiple 无法帮助他解决他想要的互斥问题。 InstanceContextMode.Single 不会修复锁。我不明白他如何解决他的问题。 大家好。我会尝试 Seymours 的建议,如果它不起作用,我会发布完整的代码,以便我们看看这里是否发生了其他事情:) 感谢 Semour,您的建议奏效了。我想投票给它,但它似乎没有给我选择:)

以上是关于WCF PerCall 共享资源锁定问题的主要内容,如果未能解决你的问题,请参考以下文章

WCF 是不是使用 ThreadPool 为 PerCall 服务启动新实例?

具有 DI 和 InstanceContextMode.Percall 的自定义 ServiceHost

WCF 可靠性问题

线程和对共享列表的访问

WCF 服务的多个应用程序域导致并发问题

MemoryCache 和多个每次调用 WCF 服务