"线程安全"对象的含义是什么?

Jas*_*wal 6 c# collections multithreading

我在C#集合中使用了通用队列,每个人都说由于线程安全,最好使用System.Collection.Generic.Queue的对象.

请告知正确使用Queue对象的决定,以及它是如何安全的?

Eri*_*ert 26

"线程安全"是一个不幸的术语,因为它并没有真正的定义.基本上,这意味着当通过多个线程操作对象时,保证对象上的某些操作表现得很明智.

考虑最简单的例子:一个计数器.假设您有两个递增计数器的线程.如果事件顺序如下:

  • 线程一从计数器读取,得到零.
  • 线程从计数器读取两次,得到零.
  • 线程1递增零,将一个写入计数器.
  • 线程2增量为零,将一个写入计数器.

然后注意计数器如何"丢失"其中一个增量.计数器上的简单增量操作不是线程安全的; 为了使它们成为线程安全的,你可以使用锁或InterlockedIncrement.

与队列类似.非线程安全队列可以"丢失"排队,就像非线程安全计数器失去增量一样.更糟糕的是,如果您在多线程场景中使用它们不正确,那么线程安全队列甚至不会崩溃或产生疯狂的结果.

"线程安全"的难点在于它没有明确定义.它只是意味着"不会崩溃"吗?这是否意味着会产生明智的结果?例如,假设您有一个"threadsafe"集合.这段代码是否正确?

if (!collection.IsEmpty) Console.WriteLine(collection[0]);
Run Code Online (Sandbox Code Playgroud)

不.即使该集合是"线程安全的",这并不意味着此代码是正确的; 另一个线程可能在检查之后但在写入线之前使集合变空,因此即使对象被称为"线程安全",此代码也可能崩溃.实际上确定每个相关的操作组合都是线程安全的是一个非常困难的问题.

现在来看看你的实际情况:任何告诉你"你应该使用Queue类,它更好,因为它是线程安全"的人可能并不清楚他们在谈论什么.首先,Queue不是线程安全的.其次,如果你只是在一个线程上使用对象,那么Queue是否是线程安全是完全无关紧要的!如果你有一个将在多个线程上访问的集合,那么,正如我在上面的例子中指出的那样,无论集合本身是否是"线程安全",你都有一个非常难以解决的问题.您必须确定您对集合执行的每个操作组合都是线程安全的.这是一个非常困难的问题,如果它是你面临的问题,那么你应该使用专家的服务来解决这个难题.

  • +1为坚实的专家证词.您也正确地指出"线程安全"是一个相当模糊的概念. (5认同)

And*_*are 5

可以从多个线程安全地访问线程安全的类型,而无需考虑并发性.这通常意味着该类型是只读的.

有趣的是,Queue<T>不是线程安全的 - 它可以支持并发读取,只要队列没有被修改但是与线程安全不同.

为了考虑线程安全性,考虑如果两个线程正在访问a Queue<T>并且第三个线程出现并开始添加或从中删除将会发生什么Queue<T>.由于此类型不限制此行为,因此它不是线程安全的.