具有异步支持的进程同步/信令的互斥替代方案? [英] Mutex alternative for process synchronisation/signalling with async support?

查看:45
本文介绍了具有异步支持的进程同步/信令的互斥替代方案?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

除了 Mutex 之外,还有什么可以容错方式同步两个进程吗?请多多包涵...

Is there anything except for Mutex to synchronise two processes in a fault-tolerant fashion? Please bear with me...

有一个进程A,它有点片状,需要在后台启动进程B并继续.如果进程 A 成功完成它的工作,它需要向进程 B 发出信号以进行处理,然后继续(它不会终止并且线程被重用).如果进程 A 因异常、终止等原因死亡,进程 B 需要快速检测并自行处理.进程 A 不是一个进程",而是一个由各种主机执行的库,因此进程 B 不能只是等待进程 A 的名字消失.

There is a process A, it's a bit flaky, it needs to start process B in the background and continue. If process A successfully does its thing, it needs to signal process B to dispose, and moves on (it doesn't terminate and thread is reused). If process A dies due to exception, termination, etc. process B needs to detect it quickly and dispose of itself on its own. Process A is not a "process" rather a library executed by various hosts hence process B can't just wait for process A's name to disappear.

进入互斥锁.

这里的进程 A 由一个测试夹具表示,如果成功,它将调用 TestFixtureTearDown 并继续前进,否则测试运行器可能会被杀死并且 TestFixtureTearDown 永远不会执行.与实际过程一样,TestFixtureTearDown 可能由与运行 TestFixtureSetUp 并创建互斥锁的线程不同的线程调用,因此 ReleaseMutex 有时会抛出 ApplicationException : 从未同步的代码块调用对象同步方法.

Here process A represented by a test fixture, if successful it'll call TestFixtureTearDown and move on, or test runner might be killed and TestFixtureTearDown is never executed. As with the actual process, TestFixtureTearDown might be called by a different thread to one that ran TestFixtureSetUp and created the mutex, hence ReleaseMutex sometimes throws ApplicationException : Object synchronization method was called from an unsynchronized block of code.

  1. 如果 TestFixtureTearDown 中的 ReleaseMutex 由不同的线程执行,我可以强制它吗?或者以其他方式放弃互斥锁?

  1. Can I force ReleaseMutex in TestFixtureTearDown if it's being executed by a different thread or abandon mutex some other way?

对于这种容错的反向"等待/监控场景,是否有替代互斥锁的方法?最好不实现进程 A 向进程 B 和进程 B 发送心跳跟踪间隔和超时?除了异步上偶尔出现的 ApplicationException 之外,Mutex 感觉是一个如此优雅的解决方案.

Is there an alternative to Mutex that I can use for such fault-tolerant "reverse" wait/monitor scenario? Preferably without implementing process A sending heartbeats to process B and process B tracking intervals and timing out? Mutex felt like such an elegant solution except for occasional ApplicationException on asyncs.

.

namespace ClassLibrary1
{
    public class Class1
    {
        private Mutex _mutex;
        private Process _process;

        [TestFixtureSetUp]
        public void TestFixtureSetUp()
        {
            _mutex = new Mutex(true, "foo");
            _process = Process.Start("ConsoleApplication1.exe");
        }

        [Test]
        public void Test1() { /* Do stuff */ }

        [Test]
        public void Test2() { /* Do async stuff */ }

        [TestFixtureTearDown]
        public void TestFixtureTearDown()
        {
            _mutex.ReleaseMutex();
            _process.WaitForExit();
        }
    }
}

.

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
        }
    }
}

推荐答案

我最终混合使用了 MutexThreadManualResetEvent.对于未来使用谷歌搜索的人来说,这里有一个详细的测试:

I ended up using a mix of Mutex, Thread and ManualResetEvent. For the googling folk of the future here's a verbose test:

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();
        }
    }
}

这篇关于具有异步支持的进程同步/信令的互斥替代方案?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆