Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.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#_Mutex - Fatal编程技术网

C# 进程同步/信令的互斥替代方案,支持异步?

C# 进程同步/信令的互斥替代方案,支持异步?,c#,mutex,C#,Mutex,除了互斥之外,还有什么方法可以以容错方式同步两个进程吗?请容忍我 有一个过程a,它有点不稳定,它需要在后台启动过程B并继续。若进程A成功地完成了它的任务,它需要通知进程B进行处理,然后继续(它不终止,线程被重用)。如果进程A因异常、终止等原因死亡,进程B需要快速检测并自行处理。进程A不是一个“进程”,而是一个由不同主机执行的库,因此进程B不能只等待进程A的名称消失 输入互斥 这里,一个由测试夹具表示的进程,如果成功,它将调用TestFixtureTearDown并继续,或者测试运行程序可能会被终

除了
互斥
之外,还有什么方法可以以容错方式同步两个进程吗?请容忍我

有一个过程a,它有点不稳定,它需要在后台启动过程B并继续。若进程A成功地完成了它的任务,它需要通知进程B进行处理,然后继续(它不终止,线程被重用)。如果进程A因异常、终止等原因死亡,进程B需要快速检测并自行处理。进程A不是一个“进程”,而是一个由不同主机执行的库,因此进程B不能只等待进程A的名称消失

输入互斥

这里,一个由测试夹具表示的进程,如果成功,它将调用
TestFixtureTearDown
并继续,或者测试运行程序可能会被终止,并且永远不会执行
TestFixtureTearDown
。与实际进程一样,
testfixturedeardown
可能被运行
TestFixtureSetUp
并创建互斥体的线程调用,因此
ReleaseMutex
有时抛出
ApplicationException:从未同步的代码块调用对象同步方法。

  • 如果由不同的线程执行,我可以在
    TestFixtureTearDown
    中强制
    ReleaseMutex
    ,还是以其他方式放弃互斥

  • 对于这种容错的“反向”等待/监视场景,我是否可以使用互斥的替代方案?最好不实施进程A,向进程B发送心跳,进程B跟踪间隔和超时?除了异步上偶尔出现的
    ApplicationException
    之外,Mutex感觉像是一个非常优雅的解决方案


  • 信号量没有线程关联。您可以在不同的线程上释放信号量,而不是在不同的线程上获取信号量。使用计数为1的信号量。

    我最后混合使用了
    互斥锁
    线程
    手动重置事件
    。对于未来的谷歌用户,这里有一个详细的测试:

    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    using NUnit.Framework;
    
    namespace MutexResetEvent.Tests
    {
        public class Class1
        {
            private Mutex _mutex;
            private Thread _thread;
            private Process _process;
            private ManualResetEvent _event;
    
            [SetUp]
            public void SetUp()
            {
                Console.WriteLine("SetUp: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                _event = new ManualResetEvent(false);
                _thread = new Thread(() =>
                {
                    Console.WriteLine("Thread: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                    _mutex = new Mutex(true, "MutexResetEvent");
    
                    _process = new Process
                    {
                        StartInfo =
                        {
                            FileName = "MutexResetEvent.Worker.exe",
                            //UseShellExecute = false,
                            //RedirectStandardOutput = true
                        }
                    };
                    //_process.OutputDataReceived += (o, a) => Console.WriteLine(a.Data);
                    _process.Start();
                    //_process.BeginOutputReadLine();
    
                    while (!_event.WaitOne(1000))
                        Console.WriteLine("Thread: ...");
    
                    Console.WriteLine("Thread: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                    _mutex.ReleaseMutex();
                    _process.WaitForExit();
                });
            }
    
            [Test]
            public void Test()
            {
                Console.WriteLine("Test: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                _thread.Start();
    
                for (var i = 0; i < 3; i++)
                {
                    Console.WriteLine("Test: ...");
                    Thread.Sleep(1000);
                }
    
                /*
                if (Guid.NewGuid().GetHashCode() % 3 == 0)
                    Environment.Exit(1);
                //*/
            }
    
            [TearDown]
            public void TearDown()
            {
                Console.WriteLine("TearDown: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                Task.Run(() =>
                {
                    Console.WriteLine("Task: #{0}", Thread.CurrentThread.ManagedThreadId);
                    _event.Set();
                    //_thread.Join();
                }).Wait();
    
                for (var i = 0; i < 3; i++)
                {
                    Console.WriteLine("TearDown: ...");
                    Thread.Sleep(1000);
                }
            }
        }
    }
    

    谢谢,我一直在考虑信号量,但找不到任何关于如何复制
    放弃的MutexException
    行为的信息,即当启动进程意外终止并且没有发出完成信号时。这一切都发生在一边是心跳,另一边是超时。它有一个废弃的状态/事件吗?我没想到。我不认为信号灯是答案。下一个想法是让库使用所选的任何IPC机制将其运行的PID传输到“watcher”进程。然后,您可以等待进程终止。
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var mutex = Mutex.OpenExisting("foo");
    
                // Start doing stuff
    
                try { mutex.WaitOne(); }
                catch (AbandonedMutexException) { }
                finally { mutex.ReleaseMutex(); }
    
                // Finish doing stuff
            }
        }
    }
    
    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    using NUnit.Framework;
    
    namespace MutexResetEvent.Tests
    {
        public class Class1
        {
            private Mutex _mutex;
            private Thread _thread;
            private Process _process;
            private ManualResetEvent _event;
    
            [SetUp]
            public void SetUp()
            {
                Console.WriteLine("SetUp: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                _event = new ManualResetEvent(false);
                _thread = new Thread(() =>
                {
                    Console.WriteLine("Thread: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                    _mutex = new Mutex(true, "MutexResetEvent");
    
                    _process = new Process
                    {
                        StartInfo =
                        {
                            FileName = "MutexResetEvent.Worker.exe",
                            //UseShellExecute = false,
                            //RedirectStandardOutput = true
                        }
                    };
                    //_process.OutputDataReceived += (o, a) => Console.WriteLine(a.Data);
                    _process.Start();
                    //_process.BeginOutputReadLine();
    
                    while (!_event.WaitOne(1000))
                        Console.WriteLine("Thread: ...");
    
                    Console.WriteLine("Thread: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                    _mutex.ReleaseMutex();
                    _process.WaitForExit();
                });
            }
    
            [Test]
            public void Test()
            {
                Console.WriteLine("Test: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                _thread.Start();
    
                for (var i = 0; i < 3; i++)
                {
                    Console.WriteLine("Test: ...");
                    Thread.Sleep(1000);
                }
    
                /*
                if (Guid.NewGuid().GetHashCode() % 3 == 0)
                    Environment.Exit(1);
                //*/
            }
    
            [TearDown]
            public void TearDown()
            {
                Console.WriteLine("TearDown: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                Task.Run(() =>
                {
                    Console.WriteLine("Task: #{0}", Thread.CurrentThread.ManagedThreadId);
                    _event.Set();
                    //_thread.Join();
                }).Wait();
    
                for (var i = 0; i < 3; i++)
                {
                    Console.WriteLine("TearDown: ...");
                    Thread.Sleep(1000);
                }
            }
        }
    }
    
    using System;
    using System.Threading;
    
    namespace MutexResetEvent.Worker
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Worker: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                var mutex = Mutex.OpenExisting("MutexResetEvent");
    
                try
                {
                    while (!mutex.WaitOne(1000))
                        Console.WriteLine("Worker: ...");
                }
                catch (AbandonedMutexException)
                {
                    Console.WriteLine("Worker: AbandonedMutexException");
                }
    
                Console.WriteLine("Worker: #{0}", Thread.CurrentThread.ManagedThreadId);
    
                mutex.ReleaseMutex();
                Console.WriteLine("Worker: WOO HOO");
    
                Console.ReadLine();
            }
        }
    }