【发布时间】:2017-03-09 23:59:32
【问题描述】:
我正在尝试用这样的 IDisposable 类包装 Mutex:
public class NamedMutex : IDisposable
{
private static readonly object _syncLock = new object();
private readonly Mutex _namedMutex;
private readonly bool _createdNew;
public NamedMutex(string name)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
//lock (_syncLock)
{
_namedMutex = new Mutex(initiallyOwned: false, name: name, createdNew: out _createdNew);
}
_namedMutex.WaitOne();
}
public void Dispose()
{
//lock (_syncLock)
{
//if (_createdNew)
_namedMutex.ReleaseMutex();
_namedMutex.Dispose();
}
}
}
正如您从注释掉的代码中看到的那样,我已经尝试了几乎所有我能想到的让它工作的东西,但是要么是我的测试错误,要么上面的实现有什么不对,因为测试要么永远不会结束(可能是我无法识别的死锁,或者它因不同步的异常而崩溃)。
这是我为 LINQPad 改编的测试:
void Main()
{
var sw = Stopwatch.StartNew();
var task1 = Task.Run(async () =>
{
using (new NamedMutex("foo"))
{
Console.WriteLine(3);
await Task.Delay(TimeSpan.FromSeconds(3));
}
});
var task2 = Task.Run(async () =>
{
using (new NamedMutex("foo"))
{
Console.WriteLine(2);
await Task.Delay(TimeSpan.FromSeconds(2));
}
});
Task.WaitAll(task1, task2);
//Assert.IsTrue(sw.Elapsed.TotalSeconds >= 5);
sw.Elapsed.Dump(); // LINQPad
}
【问题讨论】:
-
你能在
NamedMutex的构造函数中放置一个断点,并告诉我们它是否超过了_namedMutex.WaitOne();行吗? -
@MattThomas 是的。如果我在它下面添加
Console.WriteLine("WaitOne");,那么它只打印一次WaitOne,然后立即打印3,它会永远挂起。 -
我刚刚在visual studio中测试了这个,第一次可以正常工作,但是所有后续尝试都失败了。然后,如果您更改互斥锁的名称,它会再次工作一次,然后在后续调用中再次失败。程序结束后似乎没有正确处理互斥锁。
-
另外,如果您在后续调用中等待的时间足够长,
Task.WaitAll会抛出一个AggregateException,其中包含一个ApplicationException,上面写着“对象同步方法是从一个未同步的代码块中调用的。” -
我想知道它是否与
async和await有关...documentation谈到在与获得它的线程相同的线程上发布它,我认为awaiting某些东西会导致随后出现的代码在不同的线程上执行?编辑:哇! Evk 打败了我
标签: c# thread-safety mutex idisposable