【问题标题】:How to have processes (not threads) in C# synchronize file system access如何让 C# 中的进程(不是线程)同步文件系统访问
【发布时间】:2015-07-24 04:46:53
【问题描述】:

今天早些时候,我正在调试一些类似这样的东西:

class Foo {

    void AccessCriticalSection() {
        try {
            if (IO.File.Exists("\\path\to\lock.txt")
                throw new Exception();
            System.IO.File.Create("\\path\to\lock.txt");
            criticalSection();          
        } catch (Exception ex) {
            // ignored
        } 
    }

    void CriticalSection() {
        // banana banana banana
        System.IO.File.Delete("\\path\to\lock.txt");
    }

}

让我们甚至不要谈论这有多可怕……但它本质上是在尝试使用一个名为 lock.txt 的文件作为其互斥体。该操作不是原子的,如果另一个进程正在使用它,其他进程只是没有通过关键部分(如果你相信的话,它们旨在能够在释放锁后继续)等等。显然它需要修复。

如何正确获取锁以跨多个进程同步对文件系统的访问?这些进程是同一进程的多个实例,因此它们可以共享一些协议,而不是专门锁定目录(即,它们可以轻松地使用等同于某些类的所有实例锁定 private final static Object lock = new Object(); 之类的东西来同步访问静态方法)

【问题讨论】:

  • 你为什么不看Mutex
  • @AdriaanStander 我喜欢我什至把它放在描述中。大声笑。

标签: c# windows multithreading


【解决方案1】:

您应该使用Mutex

一种同步原语,也可用于进程间同步

互斥锁要么是本地的,要么是命名的。要支持进程间同步,您需要使用一个命名的互斥体

命名系统互斥锁在整个操作系统中都是可见的,并且可用于同步进程的活动。


这是一个示例程序,它演示了使用共享互斥体的进程间同步。

class Program
{
    static void Main(string[] args)
    {
        const string SHARED_MUTEX_NAME = "something";
        int pid = Process.GetCurrentProcess().Id;

        using (Mutex mtx = new Mutex(false, SHARED_MUTEX_NAME))
        {
            while (true)
            {
                Console.WriteLine("Press any key to let process {0} acquire the shared mutex.", pid);
                Console.ReadKey();

                while (!mtx.WaitOne(1000))
                {
                    Console.WriteLine("Process {0} is waiting for the shared mutex...", pid);
                }

                Console.WriteLine("Process {0} has acquired the shared mutex. Press any key to release it.", pid);
                Console.ReadKey();

                mtx.ReleaseMutex();
                Console.WriteLine("Process {0} released the shared mutex.", pid);
            }
        }            
    }
}

示例程序输出:

紫色线表示共享互斥锁的控制在两个进程之间转移的点。


要同步对单个文件的访问,您应该使用基于受保护文件的规范化路径的互斥锁名称。

Here's how you can create a normalized path:

public static string NormalizePath(string path)
{
    return Path.GetFullPath(new Uri(path).LocalPath)
               .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
               .ToUpperInvariant();
}

【讨论】:

  • 我第二点 - 具体来说 - 使用命名互斥体进行跨进程同步。
  • 注意,默认情况下,命名互斥锁是特定于用户会话的,如果您希望互斥锁在机器的多个并发用户之间共享,您必须以Global\ 开头名称,例如const string SHARED_MUTEX_NAME = "Global\something";跨度>
  • @ScottChamberlain 这仅适用于运行终端服务的服务器。
  • 否,但由登录用户运行的应用程序必须使用全局前缀才能与服务共享命名互斥锁。你在看 MSDN 上的哪个页面? CreateMutex 页面msdn.microsoft.com/en-us/library/windows/desktop/… 指出快速用户切换使用终端服务会话,并包含指向内核对象命名空间页面的链接以了解更多详细信息。
  • @HarryJohnston 谢谢!这是一个重要的教训。我正在查看 Mutex (.NET) 的课程页面:msdn.microsoft.com/en-us/library/…
猜你喜欢
  • 2014-04-29
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-15
  • 2010-10-03
  • 2013-10-14
相关资源
最近更新 更多