使用共享超时获取多个锁

时间:2017-03-23 16:13:42

标签: c# multithreading locking

我有多个对象,我想用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。你认为这是一个很好的解决方案吗?

2 个答案:

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

它还没有经过足够的测试,当然它也不支持重入。你认为它在性能方面有好处吗?