锁定语句饱和度

时间:2012-08-01 00:48:23

标签: c# multithreading locking

我有这段代码:

class Program
{
    static void Main(string[] args)
    {
        TestClass instanceOfClass = new TestClass();
        while (true)
        {
            Thread threadTest = new Thread(new ParameterizedThreadStart(AddNewToClass));
            threadTest.Start(instanceOfClass);
        }
    }
    static void AddNewToClass(object parameter)
    {
        var instance = (TestClass)parameter;
        while (true)
        {
            if (instance.Contains(1))
            {
                continue;
            }
            else
            {
                instance.AddNew(1);
            }
        }
    }
}

class TestClass
{
    public Dictionary<int, string> dictionary;
    public TestClass()
    {
        dictionary = new Dictionary<int, string>();
    }
    public void AddNew(int test)
    {
        lock (dictionary)
        {
            dictionary.Add(test, "Test string");
        }
    }
    public bool Contains(int test)
    {
        lock (dictionary)
        {
            if (dictionary.ContainsKey(test))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

我想要做的是,有几个不同的线程来添加/删除Dictionary中的对象。我试过运行这个,我得到了这个例外:

  

已添加具有相同键的项目。

这似乎非常奇怪。据我所知,lock语句应该阻止有问题的字典,而TestClass.Contains(1)应该总是返回true,并且它抛出异常,因为它多次返回true(因此异常) )。

任何人都知道为什么会这样?感谢

4 个答案:

答案 0 :(得分:3)

您的Contains()方法是原子的。你的Add()方法也是如此。但是,AddNewToClass()不是。一个帖子可能会从Contains()得到一个结果...但是不能保证它何时可能暂停(或恢复)。

那是你的竞争条件。

答案 1 :(得分:2)

你的锁只保护它所包围的街区 - 这是需要保护的

static void AddNewToClass(object parameter)
    {
        var instance = (TestClass)parameter;
        while (true)
        {
            if (instance.Contains(1))
            {
                continue;
            }  
            else
            {
                instance.AddNew(1);
            }
        }
    }

if (instance.Contains(1))instance.AddNew(1);之间,您可以获得抢占。

如果你选择instance.AddItemIfMissing(1);

之类的话
public void AddItemIfMissing(int test)
{
    lock (dictionary)
    {
        if (!dictionary.ContainsKey(test))
        {
           dictionary.Add(test, "Test string");
        }
    }
}

这可以做你想要的。

答案 2 :(得分:1)

你有比赛条件。锁定后,您需要再次检查字典是否已包含相同键的项目,因为在获取锁定之前,另一个线程可能已添加该项目。但为什么重新发明轮子? Parallel Extensions库中有许多辅助类,如ConcurrentBag。或者通过Singleton Pattern仔细考虑。

答案 3 :(得分:0)

static void AddNewToClass(object parameter)
{
    var instance = (TestClass)parameter;
    while (true)
    {
        if (instance.Contains(1))
        {
            continue;
        }    // **thread switch maybe happens here will cause your problem** 
        else
        {
            instance.AddNew(1);
        }
    }
}

所以关注更好

    lock(instance)
    {
        if (instance.Contains(1))
        {
            continue;
        }    // **thread switch maybe happens here will cause your problem** 
        else
        {
            instance.AddNew(1);
        }
    }