【问题标题】:I need the using-statement to lock disposing the resource, is my custom solution robust?我需要使用语句来锁定资源配置,我的自定义解决方案是否可靠?
【发布时间】:2013-06-17 12:16:33
【问题描述】:

我处于清理非托管资源是关键部分的情况。为了解决这个问题,我改变了这个......

void SomeMethod()
{
    //work
    using (var doc = SpreadsheetDocument.Open(results.FileName, true))
    {
        //use doc.
    }
}

到这个...

public static readonly object Locker = new object();
void SomeMethod()
{
    //work
    {//scoping doc
        var doc = SpreadsheetDocument.Open(results.FileName, true);
        try
        {
             //use doc
             //At some point wrapping a critical section via lock(Locker) 
        }
        finally
        {
            lock (Locker)
            {
                if (doc != null) ((IDisposable)doc).Dispose();
            }
        }
    }
}

我相信,这是一个丑陋而脆弱的解决方案。所以,我把它改成了下面的……

public static readonly object Locker = new object();
void SomeMethod()
{
    //work
    CustomUsingWithLocker(SpreadsheetDocument.Open(results.FileName, true), Locker, doc =>
    {
        //use doc
        //At some point wrapping a critical section via lock(Locker) 
    });
}

public static void CustomUsingWithLocker<T>(T resource, object locker, Action<T> body)
    where T : class, IDisposable 
{
    try
    {
        body(resource);
    }
    finally
    {
        lock (locker)
        {
            if (resource != null) resource.Dispose();
        }
    }
}

此自定义解决方案是否可靠?我可以改进它吗?是否保证释放任何非托管资源,例如内置的 Using 语句?

【问题讨论】:

  • 当文档不是共享对象时,为什么要使用锁来保护文档?
  • 在我的 customUserWithLocker 中,doc 用于创建一个 excel 文档。如果在此期间正在处理不同的文档,则会引发超时异常。通过锁定 excel 文档创建并锁定 dispose 调用,永远不会发生超时预期。我相信文件流是在文档之间共享的。
  • 使用来自 ASP.NET 的 Office Interop 或其他服务器技术是一个可怕的想法。这些 API 是为在桌面应用程序中使用而编写的,用于自动化 Office(一套桌面应用程序)。服务器应用程序在很多方面都不同,这使得在其中使用 Office Interop 成为一个非常非常糟糕的主意。它也不受 Microsoft 支持,并且可能违反您的 Office 许可证。见Considerations for server-side Automation of Office

标签: c# .net multithreading generics using-statement


【解决方案1】:

这里的前提似乎是多个线程多次调用Dispose。如果是这种情况,请改变这个前提。即使doc 被传递到......在另一个线程中使用它的某个地方,那个其他地方也不负责处理它,也不应该处理它。找到在using 末尾之外的位置,并将其更改为不这样做。

如果 Dispose 没有在其他地方调用,而您只是有一个非线程安全的 Dispose 方法,不应该从多个线程访问(即使您的代码当前是足够聪明,不会那样做)并且您只是在尝试应用良好的防御性编程,我认为可以肯定地说这里不需要。在这个特定的上下文中,这个方法的一个有效约束是说只有一个线程应该负责处理对象。

【讨论】:

  • 我相信Dispose 只被调用一次,在finally 部分。如果一个文档位于关键部分(特别是在创建 excel 文档时),而另一个文档正在处理,则会引发异常。当我用某种通用互斥体包装临界区和处置时,我没有遇到异常。所以,我相信你是对的,Dispose 不是线程安全的。我认为该文档正在共享文件流(很差)。总体过程由SemaphoreSlim(2) 包裹,并且创建文档发生在接近处置时,这就是它们经常发生冲突的原因。
猜你喜欢
  • 2016-03-31
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 2010-12-31
  • 2019-11-30
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
相关资源
最近更新 更多