当前位置: 首页 > 知识库问答 >
问题:

在C#中使用IDisposable模式同步访问资源的方法

羊和光
2023-03-14

我正在考虑一种使用IDisposable模式来同步/协调对共享资源的访问的方法。

以下是我到目前为止的代码(易于使用LinqPad运行):

#define WITH_CONSOLE_LOG
//better undefine WITH_CONSOLE_LOG when testing long loops

public abstract class SynchronizedAccessBase
{
    private readonly object syncObj = new();

    private class AccessToken : IDisposable
    {
        private SynchronizedAccessBase parent;
        private bool didDispose;

        public AccessToken(SynchronizedAccessBase parent)
        {
            this.parent = parent;
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.didDispose)
            {
                Monitor.Exit(this.parent.syncObj);
#if WITH_CONSOLE_LOG
                Console.WriteLine("Monitor.Exit by Thread=" + Thread.CurrentThread.ManagedThreadId);
#endif
                if (disposing)
                {
                    //nothing specific here
                }
                this.didDispose = true;
            }
        }
        ~AccessToken()
        {
            this.Dispose(disposing: false);
        }

        void IDisposable.Dispose()
        {
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
    }

    public IDisposable WantAccess()
    {
        Monitor.Enter(this.syncObj);
#if WITH_CONSOLE_LOG
        Console.WriteLine("Monitor.Enter by Thread=" + Thread.CurrentThread.ManagedThreadId);
#endif
        return new AccessToken(this);
    }
}

public class MyResource : SynchronizedAccessBase
{
    public int Value;
}

private MyResource TheResource;

private void MyMethod()
{
    using var token = TheResource.WantAccess(); //comment out this line to see the unsynced behavior
#if WITH_CONSOLE_LOG    
    Console.WriteLine("Inc'ing Value by Thread=" + Thread.CurrentThread.ManagedThreadId);
#endif
    TheResource.Value++;
}

void Main()
{
    this.TheResource = new MyResource();
    
    var inc_tasks = new Task[10];
    for (int i = 0; i < inc_tasks.Length; i++)
        inc_tasks[i] = Task.Run(() =>
        {
            for (int loop = 1; loop <= 100; loop++)
                MyMethod();
        });

    Task.WaitAll(inc_tasks);

    Console.WriteLine("End of Main() with Value==" + TheResource.Value);
}

我试图实现的是在(独占)访问共享资源之前,在方法的顶部(或者中间的某个地方,谁在乎呢)使用C#“using”语句,并让IDisposable机制自动结束独占访问。

在引擎盖下,Monitor类用于此目的。

所需的优点是不需要缩进的{代码块}。只是在使用...行就这样。请参阅上面示例中的MyMethod()。

这似乎很管用。所有inc的最终结果都是预期的,即使有很长的循环,如果我移除使用…来自MyMethod的语句。

但是,你觉得我能信任这个解决方案吗?是.dispose这个令牌真的,真的总是在离开MyMethod时调用,即使是在异常的情况下?其他陷阱?

谢谢!

共有1个答案

羊舌昆杰
2023-03-14

我一点也不觉得这有什么不妥。我以前以类似的方式使用过using模式,没有问题。

作为一个简单的示例,请考虑使用数据库连接的模式。在下面有一个连接池,从池中创建一个新的连接获取(可能是等待),并将发布释放回池。这是相同的,你有,所有的它与一个池1项。

我不知道如果资源只在一个进程内共享,那么不使用简单的lock(){}模式是否值得。那就更“传统”了。但只有你能回答。

 类似资料:
  • 10.4. 使用资源同步的事务 现在应该比较清楚的是:不同的事务管理器是如何创建的,以及它们如何被连接到相应的需要被同步到事务的资源上(例如,DataSourceTransactionManager对应到JDBC DataSource, HibernateTransactionManager对应到Hibernate的SessionFactory等)。可是,剩下的问题是,直接或间接地使用一种持久化A

  • 本文向大家介绍C#中使用资源的方法分析,包括了C#中使用资源的方法分析的使用技巧和注意事项,需要的朋友参考一下 本文实例分析了C#中使用资源的方法。分享给大家供大家参考。具体如下: 这里总结一个在C#中如何使用资源的方法如下: 方法一、使用本地文件 1、将本地要加入的资源文本(视频,图片,文本或其它)加入项目,比如我们现在加入一个up.bmp的图片到项目中,且放在文件夹Resources下面 2、

  • 本文向大家介绍C# 使用Proxy代理请求资源的方法步骤,包括了C# 使用Proxy代理请求资源的方法步骤的使用技巧和注意事项,需要的朋友参考一下 前言 这是上周在开发 C# 中使用 Proxy 代理时开发的一些思考和实践。主要需求是这样的,用户可以配置每次请求是否需要代理,用户可以配置 HTTP代理,HTTPS代理和代理白名单。 还是太年轻 因为一直用的C# 网络库中的HttpWebReques

  • 问题内容: 我的资源文件中有很多字符串数组,我想根据用户输入以编程方式访问它们。 因此,如果c == 12,则info应该是名称为“ n_12”的字符串数组。有没有办法做到这一点,并且避免对数百种情况进行switch语句? 谢谢 问题答案: 您可以像这样获取资源ID 然后只需使用该ID 在这里看看有关的另一个示例。

  • 本文向大家介绍SpringMVC访问静态资源的方法,包括了SpringMVC访问静态资源的方法的使用技巧和注意事项,需要的朋友参考一下 在SpringMVC中常用的就是Controller与View。但是我们常常会需要访问静态资源,如html,js,css,image等。 默认的访问的URL都会被DispatcherServlet所拦截,但是我们希望静态资源可以直接访问。该肿么办呢? 在配置文件: