除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.
我是否可以ReleaseMutex
强制TestFixtureTearDown
如果它被其他线程执行或者以其他方式放弃互斥?
是否可以替代Mutex,我可以用于这种容错"反向"等待/监控场景?优选地,不实施过程A将心跳发送到过程B并且过程B跟踪间隔和超时? Mutex感觉就像这样一个优雅的解决方案,除了偶然的ApplicationException
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
}
}
}
答案 0 :(得分:1)
信号量没有线程关联。您可以在与获取的线程不同的线程上释放信号量。使用计数为1的信号量。
答案 1 :(得分:1)
我最终使用Mutex
,Thread
和ManualResetEvent
混合使用。对于未来的谷歌搜索民众来说,这是一个冗长的测试:
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();
}
}
}