Monitor.Enter不会阻止其他任务

时间:2017-11-01 21:08:50

标签: c# concurrency locking task

我需要一种同步机制,只允许一个唯一的项同时进行。所以我使用Monitor.Enter阻止同一项上的其他并发执行。

以下是我的代码的切割版本及其验证逻辑的单元测试。

但是我看到我的收藏中的一些项目可以从Monitor.Enter获取多个不应该发生的锁,因为我没有在任何项目获得时释放锁。

为什么我看到货币集合中的某些项目有2个或有时3个作为值?

[TestClass]
public class UnitTest2
{
    public static ConcurrentDictionary<string, object> _keyLocks = 
        new ConcurrentDictionary<string, object>();

    public static object AcquireLock(string item)
    {
        object obj = _keyLocks.GetOrAdd(item, new object());
        Monitor.Enter(obj);
    }

    [TestMethod]
    public void AcquireLock_MultipleRequest_OnlyAllow1Request()
    {
        Dictionary<string, int> currencies = new Dictionary<string, int>() {
            { "USD",0 },
            { "EUR",0 },
            { "TRY",0 },
            { "AUD",0 },
            { "PLN",0 }
        };

        int totalTask = 1000;

        List<Task> tasks = new List<Task>();

        for (int i = 0; i < totalTask; i++)
        {
            string curr = currencies.Keys.ElementAt(i % currencies.Count);
            tasks.Add(Task.Factory.StartNew((obj) =>
            {
                string currStr = (string)obj;
                AcquireLock(currStr);
                currencies[currStr] += 1;

                //Monitor.Exit will be implemented 
            }, curr));
        }

        Thread.Sleep(10000);

        foreach (var item in currencies.Keys)
        {
            Assert.AreEqual(1, currencies[item]);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

  

为什么我看到货币集合中的某些项目有2个或有时3个作为值?

因为您正在使用线程池来获取锁。使用线程池意味着可以在同一线程中执行多个操作,当然,基于每个线程获取对象的监视器。即给定的线程可以多次获取同一个锁。

还要将您问题中发布的评论牢记在心。您正在以混乱,冗余的方式混合同步机制。