为什么我的代码在同步时不能正常工作?

Why my code doesn't work correctly in synchronization?

我正在使用此 class 来防止两个应用程序(一个 windows 应用程序和一个 Web 应用程序 运行 在同一个 OS 上)使用共享文件同一时间。但是我收到错误消息“对象同步方法是从未同步的代码块中调用的。”

    class SharedMutex : IDisposable
    {
        readonly Mutex mutex;

        /// <summary>
        /// This function will wait if other thread has owned the mutex
        /// </summary>
        /// <param name="name"></param>
        public SharedMutex(string name)
        {
            bool m = Mutex.TryOpenExisting(name, out mutex);
            if (m)
            {
                mutex.WaitOne();
            }
            else
            {
                mutex = new Mutex(true, name);
            }
        }

        public const string Logs = @"Global\Logs";

        public void Dispose()
        {
            mutex.ReleaseMutex();
            mutex.Dispose();
        }
    }

这就是我使用它的方式 class

using (new SharedMutex(SharedMutex.Logs))
                {
                   ///access the shared file
                }

这 class 存在于两个项目中。

注意:我不是在寻找访问文件问题的解决方案,我需要知道为什么我的代码有问题。因为我也想将此代码用于其他目的。 谢谢。

我认为这可能是由竞争条件引起的(正如 /u/Sinatr 在对问题的评论中所建议的)。

以下代码重现了该问题:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main()
        {
            var t1 = Task.Run(func1);
            var t2 = Task.Run(func2);

            Task.WaitAll(t1, t2);

            Console.WriteLine("Done. Press <ENTER>");
            Console.ReadLine();
        }

        static void func1()
        {
            using (new SharedMutex("test"))
            {
                Thread.Sleep(2000);
            }
        }

        static void func2()
        {
            using (new SharedMutex("test"))
            {
                Thread.Sleep(1000);
            }
        }
    }

    class SharedMutex : IDisposable
    {
        readonly Mutex mutex;

        public SharedMutex(string name)
        {
            bool m = Mutex.TryOpenExisting(name, out mutex);

            if (m)
            {
                mutex.WaitOne();
            }
            else
            {
                Thread.Sleep(10); // Simulate a short delay.
                mutex = new Mutex(true, name);
            }
        }

        public void Dispose()
        {
            mutex.ReleaseMutex();
            mutex.Dispose();
        }
    }
}

注意短暂的延迟 Thread.Sleep(10) 这足以在我的系统上引发异常,运行 调试版本。可能必须增加延迟才能在其他系统上引发异常。

如果这确实是问题所在,请按以下方法解决:

class SharedMutex : IDisposable
{
    readonly Mutex mutex;

    public SharedMutex(string name)
    {
        mutex = new Mutex(false, name);
        mutex.WaitOne();
    }

    public void Dispose()
    {
        mutex.ReleaseMutex();
        mutex.Dispose();
    }
}

你真的不在乎它是不是新创建的。 Mutex 构造函数会为您处理这些。

即使这不是问题,我仍然认为您应该使用上面的实现,因为它没有潜在的竞争条件。

the documentation for the constructor Mutex(bool, string)所述:

If name is not null and initiallyOwned is true, the calling thread owns the mutex only if the named system mutex was created as a result of this call. Since there is no mechanism for determining whether the named system mutex was created, it is better to specify false for initiallyOwned when calling this constructor overload.