c#进程间获取/释放资源计数[关闭]

Posted

技术标签:

【中文标题】c#进程间获取/释放资源计数[关闭]【英文标题】:c# inter process acquire/release resource count [closed] 【发布时间】:2017-02-11 19:24:01 【问题描述】:

我有一个可能在多个进程之间共享的资源,并且在不再使用时需要清理。

在 C# 中维护跨进程的使用计数以便在不再使用时可以清理资源的最简单方法是什么?

(如果最后一个使用资源的进程死亡,只要下一个使用的资源具有有效的使用计数,就可以不释放资源)。

【问题讨论】:

“resource”没有任何意义,你必须具体。 资源无关。想象有一个任意的系统命令运行来创建资源和一个销毁它。我需要根据它的使用来管理生命周期(跨进程)。 生命周期在所有进程终止时结束。因此,您基本上没有解决方案,但要创建一些管理器,它将以任何可能的方式监视您的所有进程(它们发送 heartbit 数据包或您 ping 它们 - 没关系)并相应地管理此资源生命周期。您可以使用 Windows 服务来完成此任务。或者您可以在资源内创建信号量,最后一个减少它的进程 - 将处理资源。但是这种方法并不可靠,因为我可以关闭您的计算机 - 并且资源将永远存在。 没有。我希望释放它的进程在它不再使用时释放它。使用与进程生命周期不对应。 【参考方案1】:

您正在描述一种在 .net 远程处理中实现的模式,其中资源的使用者可能在不同的机器上。这是通过强制消费者显式释放对象来实现的,并以 Lifetime Lease 为后盾,如果消费者没有刷新租约,它会自动超时。

鉴于所有这些都已在 .net 框架中,我建议使用远程处理来生成您的框架。

【讨论】:

愿意分享一些示例代码吗?我没怎么用过remoting。 虽然它现在已经很老了(被 WCF 取代),但远程处理库模式只是拥有一个工厂(用于创建和回收资源的实例)、一个注册表(由工厂用来保存跟踪生成和租用的实例,以及租约到期时间)和消费者显式释放(通过方法调用)或更新租约的方法。您可以轻松地使用 .net Memory Cache 类来实现 this 的发布、更新和到期元素。 这听起来很复杂。希望在最多 10-20 行代码中找到一些东西。尝试内存映射文件/互斥体,我认为这可能会奏效。【参考方案2】:

如果所有进程都在同一台机器上,我会创建一个包含实例计数的文件。当资源由进程提供时,应该打开文件进行写入,从而有效地锁定文件。实例计数应该被读取并递增,然后文件上的写锁被释放。

当进程退出(或资源处理完毕)时,获取文件的写锁并减少资源计数。如果递减后资源计数为零,则启动清理过程。

您将必须有重试逻辑,以防第二个进程尝试在共享文件上获取写锁,而该文件已经打开以供另一个进程写入。

重要的一点是操作系统可以给你一个独占写锁,这实际上是你的关键部分。

【讨论】:

这是一个想法,但不处理硬进程退出,这样做似乎比它应该的要复杂得多(例如维护 PID 列表或系统互斥体名称)。糟糕。 只要创建一些监控进程,它就会在 processCount=0 时进行清理,即使你的进程死得很惨。 是的,那些硬退出(有人终止进程或拔掉电源线)将很难处理。我见过的另一种方法是有一个单独的应用程序,它有一个临界区,将计数序列化到磁盘,并通过 RPC 递增或递减。您可以从此类进程执行定期轮询以检查以确保所有已注册为使用该资源的进程仍然处于活动状态。已经很久了(所以我的记忆很模糊),但在旧的 COM 组件时代也存在同样的问题。我不记得当时是怎么解决的。【参考方案3】:

我使用的代码:

internal sealed class InterProcessResource 
    private static readonly string MutexNameThisProcess = "IPR-" + Guid.NewGuid().ToString();
    private static readonly Mutex MutexThisProcess = new Mutex(true, MutexNameThisProcess);

    private readonly MemoryMappedFile mmf;
    private readonly string mutexName;

    public InterProcessResource(string resourceName) 
        this.mutexName = resourceName + "-mtx";
        this.mmf = MemoryMappedFile.CreateOrOpen(resourceName + "-mmf", 16 * 1024, MemoryMappedFileAccess.ReadWrite);
    


    public void Acquire(Action initAction) 
        using (new Mutex(true, this.mutexName)) 
            var currentList = ReadStringList(mmf);
            if (currentList.Count == 0) 
                initAction();
            
            var newList = PruneMutexList(currentList);
            newList.Add(MutexNameThisProcess);
            WriteStringList(this.mmf, newList);
        
    

    public void Release(Action freeAction) 
        using (new Mutex(true, this.mutexName)) 
            var currentList = ReadStringList(this.mmf);
            var newList = PruneMutexList(currentList);
            WriteStringList(this.mmf, newList);
            if (newList.Count == 0) 
                freeAction();
            
        
    

    private static List<string> ReadStringList(MemoryMappedFile mmf) 
        var list = new List<string>();
        using (var stream = mmf.CreateViewStream()) 
            var reader = new BinaryReader(stream);
            int count = reader.ReadInt32();
            for (int i = 0; i < count; i++) 
                list.Add(reader.ReadString());
            
        
        return list;
    

    private static void WriteStringList(MemoryMappedFile mmf, List<string> newList) 
        using (var stream = mmf.CreateViewStream()) 
            var writer = new BinaryWriter(stream);
            int count = newList.Count;
            writer.Write(count);
            for (int i = 0; i < count; i++) 
                writer.Write(newList[i]);
            
        
    

    // removes our mutex name AND any dead processes mutex names
    private static List<string> PruneMutexList(List<string> list) 
        var newList = new List<string>();
        foreach (var s in list) 
            if (s != MutexNameThisProcess) 
                Mutex m;
                if (Mutex.TryOpenExisting(s, out m)) 
                    newList.Add(s);
                    m.Dispose();
                
            
        
        return newList;
    

【讨论】:

以上是关于c#进程间获取/释放资源计数[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

详细说一下C#中using自动释放资源的用法

C# 资源释放问题

C# 线程运行完之后自己会不会释放掉

sh cleanipc进程间通讯资源释放(清理)Shell脚本

C# 线程运行完之后自己会不会释放掉

C#无法访问已释放的对象