Mutex替代流程同步/信令与异步支持?

时间:2014-10-02 16:37:17

标签: c# mutex

Mutex之外还有什么能以容错的方式同步两个进程吗?请耐心等待......

有一个过程A,它有点不稳定,它需要在后台启动进程B并继续。如果进程A成功地执行了它的操作,它需要向进程B发出信号以进行处理,然后继续(它不会终止并且线程被重用)。如果进程A由于异常,终止等而死亡,则进程B需要快速检测它并自行处理。流程A不是"流程"而是由各个主机执行的库,因此进程B不能等待进程A的名称消失。

输入Mutex。

此处由测试夹具代表的过程A,如果成功,它将调用TestFixtureTearDown并继续前进,或者测试跑步者可能会被杀死并且TestFixtureTearDown永远不会被执行。与实际流程一样,TestFixtureTearDown可能会被运行TestFixtureSetUp并创建互斥锁的其他线程调用,因此ReleaseMutex有时会抛出ApplicationException : Object synchronization method was called from an unsynchronized block of code.

  1. 我是否可以ReleaseMutex强制TestFixtureTearDown如果它被其他线程执行或者以其他方式放弃互斥?

  2. 是否可以替代Mutex,我可以用于这种容错"反向"等待/监控场景?优选地,不实施过程A将心跳发送到过程B并且过程B跟踪间隔和超时? Mutex感觉就像这样一个优雅的解决方案,除了偶然的ApplicationException asyncs。

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

我最终使用MutexThreadManualResetEvent混合使用。对于未来的谷歌搜索民众来说,这是一个冗长的测试:

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