我有多个对象,我想用Monitor.TryEnter
同时锁定一个超时。如果我将它们锁定,则以后对象无法开始进入锁定状态,直到之前的对象被锁定,导致后续对象的超时时间减少,因此成功锁定的机会减少:
Monitor.TryEnter(A, 10000);
Monitor.TryEnter(B, 10000 - passedA); // smaller timeout
Monitor.TryEnter(C, 10000 - passedAB); // even smaller timeout
我可以让它们同时开始锁定吗?
我想要Monitor.TryEnterMany(new[] {A, B, C}, 10000)
。
我想我可以使用AutoResetEvent
代替锁定,以便输入"锁定我会在所有事件上调用WaitAll
并发布"发布"我会在每个人上面打Set
。你认为这是一个很好的解决方案吗?
答案 0 :(得分:1)
使用Mutex
代替AutoResetEvent
:
Mutex A = new Mutex(), B = new Mutex(), C = new Mutex();
Mutex[] waitHandles = new[] { A, B, C };
WaitHandle.WaitAll(waitHandles, 10000);
// Do stuff.
foreach(Mutex mutex in waitHandles)
{
mutex.ReleaseMutex();
}
答案 1 :(得分:0)
我想我可以使用AutoResetEvent代替锁定,以便"输入" 锁我会在所有事件上调用WaitAll并发布"发布"我会打电话 设置在每一个上。
所以这看起来很有效,这里是代码:
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication16
{
class Program
{
static void Main(string[] args)
{
// checks that WaitAll doesn't reset first event on timeout
var ev1 = new AutoResetEvent(true);
var ev2 = new AutoResetEvent(false);
WaitHandle.WaitAll(new [] { ev1, ev2}, 1000);
ev1.WaitOne();
int counter = 0;
var m = new MyMonitor();
var m2 = new MyMonitor();
var tasks = Enumerable.Range(0, 1000).Select(
x => Task.Run(
() =>
{
for (int i = 1; i <= 1000; i++)
{
if (!MyMonitor.TryAcquireMany(100000, m, m2)) throw new TimeoutException();
counter++;
m.Release();
m2.Release();
}
})).ToArray();
Task.WaitAll(tasks);
Console.WriteLine(counter + " should be " + (1000 * 1000));
Console.ReadLine();
}
}
class MyMonitor
{
readonly AutoResetEvent _event = new AutoResetEvent(true);
public static bool TryAcquireMany(int timeout, params MyMonitor[] monitors)
{
return WaitHandle.WaitAll(monitors.Select(x => (WaitHandle)x._event).ToArray(), timeout);
}
public bool TryAcquire(int timeout)
{
return _event.WaitOne(timeout);
}
public void Release()
{
_event.Set();
}
}
}
它还没有经过足够的测试,当然它也不支持重入。你认为它在性能方面有好处吗?