Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.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# 何时在.net中锁定线程安全集合?(&;何时不锁定?)_C#_.net_Multithreading_Concurrency_Task Parallel Library - Fatal编程技术网

C# 何时在.net中锁定线程安全集合?(&;何时不锁定?)

C# 何时在.net中锁定线程安全集合?(&;何时不锁定?),c#,.net,multithreading,concurrency,task-parallel-library,C#,.net,Multithreading,Concurrency,Task Parallel Library,好的,我已经读过了 前一个问题是以java为中心的,它没有回答我的问题,而后一个问题的答案告诉我,我不需要锁定集合,因为它们应该是线程安全的。(我就是这么想的) 现在来问我的问题, 我看到很多开发人员(在github和我的组织中)已经开始使用新的线程安全集合。但是,它们通常不会在读写操作周围移动锁。 我不明白。不是线程安全的集合。。。完全线程安全 不锁定线程安全的集合会带来什么影响? 编辑:PS:这是我的案例 我有很多类,其中一些类有一个属性。我经常需要检查给定类型是否具有该属性(当然使用反

好的,我已经读过了

前一个问题是以java为中心的,它没有回答我的问题,而后一个问题的答案告诉我,我不需要锁定集合,因为它们应该是线程安全的。(我就是这么想的)


现在来问我的问题, 我看到很多开发人员(在github和我的组织中)已经开始使用新的线程安全集合。但是,它们通常不会在读写操作周围移动锁。 我不明白。不是线程安全的集合。。。完全线程安全


不锁定线程安全的集合会带来什么影响?

编辑:PS:这是我的案例

我有很多类,其中一些类有一个属性。我经常需要检查给定类型是否具有该属性(当然使用反射)。这在性能上可能很昂贵。因此决定使用
ConcurrentDictionary
创建缓存。字符串是typeName,bool指定它是否具有属性。起初,缓存是空的,计划是在需要时继续添加到缓存中。我遇到了
ConcurrentDictionary
的方法。我的问题也是一样,如果我调用这个方法而不锁定

MSDN上的评论说:

如果在不同线程上同时调用GetOrAdd, 可以多次调用addValueFactory,但不能调用其键/值对 可能不会每次调用都添加到词典中


您不应该锁定线程安全的集合,它会公开方法来更新已锁定的集合,并按预期使用它们

线程安全集合可能不符合您的需要,例如,如果您希望在集合上打开枚举数时阻止修改(提供的线程安全集合允许修改)。如果是这样的话,你最好使用一个常规的集合,并将其锁定在任何地方。线程安全集合的内部锁不公开

很难回答不锁定线程安全集合的含义。您不需要锁定线程安全的集合,但可能必须锁定执行多种操作的代码。看不到代码就很难说


是的,该方法是线程安全的,但是如果同时为同一个键点击Add,它可能会多次调用AddValueFactory。最后,只添加一个值,其他值将被丢弃。这可能不是一个问题。。。你必须检查你多久会遇到这种情况,但我认为这并不常见,你可以在一种可能永远不会发生的边缘情况下承受性能损失


您还可以在静态ctor中或在需要之前构建您的词汇表。这样的话,词汇表只填写一次,你就永远不会给它写信了。然后,字典是只读的,您不需要任何锁,也不需要线程安全集合。

类的方法通常会将对象从状态a更改为状态B。但是,另一个线程也可能在该方法执行期间更改对象的状态,从而可能使对象处于不稳定状态

例如,在添加新项之前,列表可能需要检查其基础数据缓冲区是否足够大:

void Add(object item)
{
    int requiredSpace = Count + 1;
    if (buffer.Length < requiredSpace)
    {
        // increase underlying buffer
    }

    buffer[Count] = item;
}
虽然集合是线程安全的,但是您仍然需要考虑自己的代码的线程安全性。Guillaume提到的枚举器示例是线程问题可能发生的地方的完美示例

关于您的评论,文件中提到:

所有这些操作都是原子操作,对于ConcurrentDictionary类上的所有其他操作都是线程安全的。唯一的例外是接受委托的方法,即AddOrUpdate和GetOrAdd。对于字典的修改和写入操作,ConcurrentDictionary使用细粒度锁定来确保线程安全。(字典上的读取操作是以无锁方式执行的。)但是,这些方法的委托在锁之外调用,以避免在锁下执行未知代码时可能出现的问题。因此,这些委托执行的代码不受操作原子性的约束


因此,是的,这些重载(接受委托)是例外。

它公开的方法是线程安全的吗?看看MSDN上的评论(见更新的问题),微软似乎不保证这一点。我已经更新了问题以反映我当前的情况。在阅读了你和纪尧姆的答案后,我查看了MSDN(见相关评论)。现在我担心的是MSDN的报价。这似乎不确定。@BilalFazlani我理解您的担忧,但它似乎只影响这些方法的某些重载。更新了我的答案。我明白了,现在开始有意义了。通过仔细阅读,在我看来,尽管委托将在锁外执行,但委托返回的值只有在锁定后才会添加到字典中。如果这是真的,我觉得使用
ConcurrentDictionary
而不锁定它是安全的。
int count = myConcurrentCollection.Count;
myCurrentCollection.Add(item);
count++;
if (myConcurrentCollection.Count != count)
{
    // some other thread has added or removed an item
}