Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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# 添加到列表但不读取列表时的竞争条件<;T>;(或堆栈或队列)-发生了什么?_C#_Multithreading_Concurrency - Fatal编程技术网

C# 添加到列表但不读取列表时的竞争条件<;T>;(或堆栈或队列)-发生了什么?

C# 添加到列表但不读取列表时的竞争条件<;T>;(或堆栈或队列)-发生了什么?,c#,multithreading,concurrency,C#,Multithreading,Concurrency,注意:我问的是关于3.5框架的这个问题,所以我没有在4.0中包含任何更新的多线程结构(我还在学习) 我一直在试图找到一个关于这个问题的答案,试图结束我一直以来的争论,但我觉得我还没有找到一个关于在下面的场景中会发生什么或可能发生什么的结论性描述 假设你有一个应用程序,它有多个线程,所有线程都在生成对象,每个线程生成一个唯一的对象。集合(列表、堆栈或队列)只有一个实例,它是对象创建后的存储库,对象添加到集合后实际上是不可变的 在此过程中,对集合的唯一操作是添加项。没有进行读取、移除或计数。收藏中物

注意:我问的是关于3.5框架的这个问题,所以我没有在4.0中包含任何更新的多线程结构(我还在学习)

我一直在试图找到一个关于这个问题的答案,试图结束我一直以来的争论,但我觉得我还没有找到一个关于在下面的场景中会发生什么或可能发生什么的结论性描述

假设你有一个应用程序,它有多个线程,所有线程都在生成对象,每个线程生成一个唯一的对象。集合(列表、堆栈或队列)只有一个实例,它是对象创建后的存储库,对象添加到集合后实际上是不可变的

在此过程中,对集合的唯一操作是添加项。没有进行读取、移除或计数。收藏中物品的顺序并不重要

问题是,如果在单个线程尝试添加对象时集合周围没有锁定,这真的是个问题吗

我说是的,但是几乎所有关于为什么种族条件有问题的教科书描述,一端有一个读数,另一端有一个种族,或者写一个变量,所以我没有足够的证据来有效地论证我的论点


我之所以说是,基本上是因为集合的设计不是线程安全的,所以即使只执行“写入”,也可能会出现意外或未定义的行为。我猜想有一种风险,两个线程可能会尝试将它们的对象添加到集合中的同一个插槽中,因此当对象被覆盖时,您可能会丢失一个对象,但我还没有找到任何证据表明这确实是可能的。或者可能存在一些幕后问题,例如当集合需要自身增长以容纳更多项目时


有人能给我提供一些信息帮助我平息这场争论吗?我特别感兴趣的是,是否有任何东西可以证明我是错的。

向列表中添加项目涉及到内存的读写,因此除非有同步,否则就有竞争。

向列表中添加项目涉及内存的读写,因此除非有同步,否则就有竞争。

向列表中添加项目
列表(或堆栈等)不是线程安全的

这涉及

  • 检查内部数组大小是否足够
  • 如果没有,则创建一个新数组,复制所有项
  • 在数组中设置索引等于
    列表长度的项

上述进程都不是线程安全的,.NET framework代码中没有同步。因此,如果您不同步,我保证您的列表将被破坏。

将项目添加到
列表(或堆栈等)是不线程安全的

这涉及

  • 检查内部数组大小是否足够
  • 如果没有,则创建一个新数组,复制所有项
  • 在数组中设置索引等于
    列表长度的项

上述进程都不是线程安全的,.NET framework代码中没有同步。因此,如果您不同步,我保证您的列表将被破坏。

您基本上是对的,尽管一些较简单的结构(如堆栈或队列)可能是“意外”线程安全的。您无法保证任何集合的“内部”是如何实现的。例如,列表由数组支持。如果您添加一个新项使其增长数组,它将(可能)将所有值复制到一个新的更大的数组中。这在其实现中可能是线程安全的,但由于它不是线程安全对象,因此它的线程安全性没有契约。

您基本上是对的,尽管一些较简单的结构(如堆栈或队列)可能是“意外”线程安全的。您无法保证任何集合的“内部”是如何实现的。例如,列表由数组支持。如果您添加一个新项使其增长数组,它将(可能)将所有值复制到一个新的更大的数组中。这在其实现中可能是线程安全的,但由于它不是线程安全的对象,因此它的线程安全性不受约束。

“幕后问题,例如当集合需要自身增长以容纳更多项目时”是我的第一个猜测。“幕后问题,例如,当收藏需要自身增长以容纳更多物品时“这是我的第一个猜测。将值复制到新数组怎么可能是线程安全的?!”?!此外,假设内部实现细节在不同版本的.NET Framework中保持不变,这是在玩火。除非文档明确证明某些东西是线程安全的,否则永远不要假设它是线程安全的。@David和@Cody。我不确定你们是否不同意我的观点。我的回答与你的说法完全一致。堆栈和队列可能是线程安全的,但如果是这样,那只是“意外”而已。而列表显然不是。要点是:不要指望它,即使它在并发条件下似乎工作正常。当你说“这可能是线程安全的”时,正确的说法应该是“这肯定不是线程安全的”@MichaelMadows:没有特别的原因,可寻址索引列表不能是线程安全的,如果有人从未使用过像
Insert
Delete
这样的方法,则在添加项目后需要更改项目的代码是通过
int Add(T item)
方法执行的,该方法返回新创建项目的索引。如果
T
是一个类类型,并且列表项不允许为null,那么这样的类甚至可以是loc