Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#多线程代码访问锁内的局部变量_C#_Multithreading_Locking - Fatal编程技术网

C#多线程代码访问锁内的局部变量

C#多线程代码访问锁内的局部变量,c#,multithreading,locking,C#,Multithreading,Locking,我的问题与下面的代码有关。我简化了代码以提取问题 我知道锁可以防止foo Hashtable变量被更改,但是锁之外的变量呢?我们在代码中看到一些奇怪的行为,看起来像这样,这就是出现的问题。谢谢你的意见 using System.Collections; namespace MultithreadScratch01 { public class ThreadFoo { public void Foo(Stub2 stub2, Hashtable foo)

我的问题与下面的代码有关。我简化了代码以提取问题

我知道锁可以防止foo Hashtable变量被更改,但是锁之外的变量呢?我们在代码中看到一些奇怪的行为,看起来像这样,这就是出现的问题。谢谢你的意见

using System.Collections;

namespace MultithreadScratch01
{
    public class ThreadFoo
    {
        public void Foo(Stub2 stub2, Hashtable foo)
        {
            Stub1 bar;

            var prop1 = stub2.Prop1;
            var prop2 = stub2.Prop2;
            var prop3 = stub2.Prop3;

            var hash = string.Format("{0}_{1}_{2}", prop1, prop2, prop3);

            lock(foo)
            {
                if(!foo.Contains(hash))
                {
                    bar = new Stub1 {Foo = "some arbitrary string", Bar = 123};
                    foo.Add(hash, bar);
                }
            }

        }
        public class Stub1
        {
            public string Foo { get; set; }
            public int Bar { get; set; }
        }
        public class Stub2
        {
            public string Prop1 { get; set; }
            public string Prop2 { get; set; }
            public string Prop3 { get; set; }

        }
    }
}

防止更改foo哈希表变量


简单地;同一对象上锁定的两个线程不能同时在锁内。如果您有任何代码没有在同一对象(哈希表)上锁定,它将直接进入,并可能造成损坏。关于其他变量。。。如果有任何东西正在改变对象,并且没有锁定与您相同的锁定对象,那么事情可能会变得很糟糕。实际上,如果它锁定在同一个对象上,甚至会出现一些边缘情况(如果将属性移动到内部锁定
,这将得到解决)。但是,由于这些变量不是“捕获”的,因此一旦您有了值的快照,快照就不会更改。

您对锁的操作有些误解。它不是阻止其他线程访问或修改
foo
,而是实际上阻止其他线程进入锁包围的代码块。如果在其他地方修改
foo
,可能会看到问题

因为
hash
是一个局部变量,所以您不应该看到它有任何问题


您可能想尝试使用
ConcurrentDictionary
而不是
Hashtable
,它是为多线程访问而设计的。

锁定参数是一个危险的游戏,正如上面提到的,因为您不知道在您的方法之外如何处理该参数。其他人可能同时在修改它


您可以将所有代码包装到方法中,以确保一次只有一个线程在该代码中,但由于Stub1和Stub2类不是线程安全的(需要对属性设置锁),因此即使这样做也不能保证在读取属性时不会更改属性

你在这里做的是多方面的“最糟糕的做法”

首先,不能保证引用该哈希表的其他线程在读写它之前也会锁定它。这就是为什么这项技术如此糟糕;很难做出这样的保证

其次,不能保证引用该哈希表实例的其他线程不会锁定它,也无法解锁它,因为它们有缺陷或恶意。您可能会让其他人负责代码的正确性,这是一个危险的处境。一个好的规则是“永远不要锁定任何外部代码可以看到的东西”。从不锁定“this”,从不锁定类型对象,等等。有时会对这条规则破例,但我需要一个很好的理由

在这里正确的做法是首先使用ConcurrentDictionary。如果您不能做到这一点,那么我将围绕哈希表编写一个包装器:

sealed class ThreadSafeHashTable
{
    private readonly HashTable hashTable = new HashTable();
    public void Add(object key, object value)
    {
        lock(this.hashTable)
        {
            ...
现在,(1)每次调用Add时都会执行锁定,(2)只有这个类中的代码可能会执行锁定,因为被锁定的对象是私有的,永远不会被传递出去


如果你不能做这两件事中的任何一件,我会用艰难的方式来做。如果你想以艰难的方式完成这项工作,那么你必须追踪哈希表可能被使用的每个地方,并确保写入了正确的锁定代码。

哪个“锁外变量”?我认为描述“奇怪的行为”可能对你有好处这是我继承的代码,不幸的是,这是一种在一些地方重复的模式。观察到的奇数行为是错误选择的数据。至于锁外的变量,具体来说,我考虑的是散列变量。非常感谢您的快速反馈。我对多线程代码没有太多的经验,通常在可以的时候避免使用它,但我确实认为这有点难闻。我就是不知道为什么。不过,这是遗留代码,意味着我已经完成了它。再次感谢您的帮助。实际上,应该注意的是,
Hashtable
也是为多线程访问而设计的(不像
Dictionary
,Dictionary实际上不是)-区别在于,
Hashtable
对于任何数量的读卡器和最多一个编写器都是线程安全的-意思是:编写器必须同步,但读者不需要这样做,这是真的。我已经有一段时间没用了。谢谢,我同意。然而,有趣的是,VS2003文档却有相反的说法:“通常,表达式要么是this,…,要么是typeof(class)…。”它可以被更新,还是旧文档被锁定?(看到我在那里做了什么了吗?)那太不幸了!我会向文档经理提到这一点,但是是的,通常我们不会修改那么旧的文档。