代码之家  ›  专栏  ›  技术社区  ›  Jaswant Agarwal

“线程安全”对象是什么意思?

  •  6
  • Jaswant Agarwal  · 技术社区  · 16 年前

    我在C#collection中使用了generic queue,每个人都说最好使用System.collection.generic.queue的对象,因为线程安全。

    请说明使用队列对象的正确决定,以及它如何是线程安全的?

    3 回复  |  直到 16 年前
        1
  •  30
  •   Eric Lippert    16 年前

    “线程安全”是一个有点不幸的术语,因为它没有一个可靠的定义。基本上,这意味着当通过多个线程对对象进行操作时,可以保证对象上的某些操作的行为是合理的。

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

    • 线程一从计数器读取,得到 零。
    • 线程2递增0,写入

    然后注意计数器是如何“丢失”一个增量的。计数器上的简单增量操作不是线程安全的;为了使它们具有线程安全性,可以使用锁或联锁增量。

    与队列类似。非线程安全队列可以“丢失”排队,就像非线程安全计数器可以丢失增量一样。更糟糕的是,如果在多线程场景中使用不当,非线程安全队列甚至可能崩溃或产生疯狂的结果。

    “线程安全”的困难在于它没有明确的定义。它仅仅意味着“不会崩溃”吗?这是否意味着会产生合理的结果?例如,假设您有一个“threadsafe”集合。这个代码正确吗?

    if (!collection.IsEmpty) Console.WriteLine(collection[0]);
    

    不,即使集合是“线程安全的”,也不意味着这个代码是正确的;另一个线程可能在检查之后但在writeline之前使集合为空,因此此代码可能会崩溃,即使对象据称是“线程安全的”。实际上决定了 所有相关组合 操作的线程安全性是一个极其困难的问题。

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

        2
  •  5
  •   Andrew Hare    16 年前

    有趣的是, Queue<T> 是 不

    排队<T> 第三条线索出现了,开始添加或删除 排队<T> . 由于此类型不限制此行为,因此它不是线程安全的。

        3
  •  1
  •   Platinum Azure    16 年前

    在处理多线程时,通常必须处理并发问题。术语“并发性问题”指的是通过将来自两个不同执行上下文的指令交织在两者共享的资源上的可能性而具体引入的问题。这里,就线程安全而言,执行上下文是进程内的两个线程;然而,在相关学科中,它们可能是过程。

    test-and-set 指令等,以及软件级别 synchronization constructs 当另一个执行上下文正在执行不应中断的工作时,强制所有其他执行上下文远离该数据类型。

    通常,只读对象是线程安全的。许多对象不是只读的,如果中间没有修改对象,则可以在没有问题的情况下多个线程发生数据访问(只读)。但这不是线程安全。线程安全是指对一个数据类型执行各种操作,以防止一个线程对其进行的任何修改导致数据损坏或死锁,即使在处理许多并发读写时也是如此。