Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于带计数器的命名互斥锁的C#线程安全锁_C#_Multithreading_Mutex_Semaphore_Named - Fatal编程技术网

基于带计数器的命名互斥锁的C#线程安全锁

基于带计数器的命名互斥锁的C#线程安全锁,c#,multithreading,mutex,semaphore,named,C#,Multithreading,Mutex,Semaphore,Named,我需要在C#中编写一个dll,以用作系统范围(windows 10)的存储库。我需要有其他应用程序的唯一命名实例,应该有可能获得实例的当前计数。它应该是线程安全的,系统范围(跨进程),不创建额外的数据库/文件,并且只使用系统组件(没有外部包)。也应该有可能提供高百分比的测试覆盖率(100就完美了)。最后一个要求是发布实例,即使开发人员在程序中忘记了它 经过研究,我的想法是使用命名互斥体来确保它是跨进程的,并在系统中维护实例的唯一名称。完成了这些之后,我使用了信号量类来获得适当的跨进程计数器。要发

我需要在C#中编写一个dll,以用作系统范围(windows 10)的存储库。我需要有其他应用程序的唯一命名实例,应该有可能获得实例的当前计数。它应该是线程安全的,系统范围(跨进程),不创建额外的数据库/文件,并且只使用系统组件(没有外部包)。也应该有可能提供高百分比的测试覆盖率(100就完美了)。最后一个要求是发布实例,即使开发人员在程序中忘记了它

经过研究,我的想法是使用命名互斥体来确保它是跨进程的,并在系统中维护实例的唯一名称。完成了这些之后,我使用了信号量类来获得适当的跨进程计数器。要发布实例,有IDisposable接口和finallizer。附加课程似乎有效,但我这边有两个问题

class GlobalLocker : IGlobalLocker, IDisposable
    {
        private static readonly string SEMAPHORE_NAME = "Global\\GlobalLockerSemaphore";
        private static Semaphore _semaphore;
        private static List<Mutex> _mutexes;

        public GlobalLocker()
        {
            _mutexes = new List<Mutex>();

            if (Semaphore.TryOpenExisting(SEMAPHORE_NAME, out _semaphore))
            {
            }
            else
            {
                _semaphore = new Semaphore(0, int.MaxValue, SEMAPHORE_NAME);
            }
        }

        ~GlobalLocker()
        {
            Dispose();
        }

        public void Dispose()
        {
            WriteLine("Void dispose method started");

            _mutexes.ForEach(x =>
            {
                x.ReleaseMutex();
                x.Dispose();
                x.Close();

                _semaphore.WaitOne(0);
            });

            _mutexes = null;

            WriteLine("Void dispose method finished");
            
        }

        public bool TryLock(string lockId)
        {
            bool mutexWasCreated;
            var mutex = new Mutex(true, "Global\\" + lockId, out mutexWasCreated);

            if (mutexWasCreated)
            {
                _semaphore.Release();

                _mutexes.Add(mutex);

                return true;
            }

            return false;
        }

        public int GetLocksCount()
        {
            _semaphore.WaitOne(0);

            return _semaphore.Release();
        }

        public static void WriteLine(string x)
        {
            Console.WriteLine($"{DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")}: { x}");
        }
    }
类GlobalLocker:iglobalocker,IDisposable
{
私有静态只读字符串信号量\u NAME=“Global\\globallockeremaphore”;
专用静态信号量\u信号量;
私有静态列表_互斥体;
公共GlobalLocker()
{
_互斥量=新列表();
if(Semaphore.TryOpenExisting(Semaphore\u NAME,out\u Semaphore))
{
}
其他的
{
_信号量=新信号量(0,int.MaxValue,信号量\名称);
}
}
~GlobalLocker()
{
处置();
}
公共空间处置()
{
WriteLine(“已启动无效处置方法”);
_mutex.ForEach(x=>
{
x、 释放互斥锁();
x、 处置();
x、 Close();
_信号量WaitOne(0);
});
_互斥量=null;
WriteLine(“无效处置方法完成”);
}
公共布尔锁(字符串锁ID)
{
创建布尔互斥;
var mutex=新的互斥体(true,“Global\\\”+lockId,out mutexwasweated);
如果(mutexWasCreated)
{
_semaphore.Release();
_添加(互斥);
返回true;
}
返回false;
}
public int getLockScont()
{
_信号量WaitOne(0);
return_semaphore.Release();
}
公共静态无效写线(字符串x)
{
Console.WriteLine($”{DateTime.Now.ToString(“MM/dd/yyyy HH:MM:ss”)}:{x});
}
}
  • 根据报告:
  • 使用一个布尔值初始化互斥体类的新实例,该布尔值指示调用线程是否应该拥有互斥体的初始所有权,一个字符串表示互斥体的名称,以及一个布尔值,该布尔值在方法返回时指示调用线程是否被授予互斥体的初始所有权

    线程具有初始所有权是否意味着它是完全线程安全的,并且没有其他线程可以影响当前实例的互斥体

  • 我做了一些烟雾测试,有一种bug/问题。有这样一个场景:打开了3个控制台应用程序,每个应用程序的实例都是GlobalLocker类,在第一个实例中,有一个锁定的互斥锁,其lockId为“one”。在那个时刻,在第三个实例中,计数器返回1,我不能用lockId“one”锁定互斥锁-一切都很完美。在第二个实例中,我用lockId“2”锁定了互斥锁,第三个实例中的计数器返回2,仍然可以。第一个实例已退出,因为代码已完成并带有消息,该Dispose方法也已成功。此时的第三个实例返回1,但在第二个实例中,我无法用lockId“one”锁定互斥锁,这在当时应该是可用的。在退出第二个实例并处理资源后,第三个实例的计数器返回0,我可以同时锁定LockID“1”和“2”

  • 有人能向我解释一下,为什么退出了第一个互斥锁却没有被释放?是什么导致了这种差异,即在退出第二个实例时,它们都被释放了?

    初始所有权意味着如果它是真的,并且
    mutexwastcreated
    out变量也返回了真-那么调用者现在拥有互斥体,而不显式调用
    WaitOne
    。至于第二部分,如果您包含复制错误的测试代码,则会更容易。错误不是由于测试代码而产生的,而是手动进行的冒烟测试。