【问题标题】:Should access to a shared resource be locked by a parent thread before spawning a child thread that accesses it?在生成访问共享资源的子线程之前,是否应该由父线程锁定对共享资源的访问?
【发布时间】:2010-02-10 08:50:42
【问题描述】:

如果我有以下伪代码:

sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);

理论上,多核 CPU 是否可以在 threadWhichUsesSharedVariable() 中执行代码,该代码在父线程写入之前读取 sharedVariable 的值?为了在理论上完全避免竞争条件的可能性,代码应该看起来像这样:

sharedVariableMutex.lock();
sharedVariable = somevalue;
sharedVariableMutex.unlock();
CreateThread(threadWhichUsesSharedVariable);

基本上我想知道线程的产生是否在那时显式地线性化了 CPU,并且保证会这样做。

我知道线程创建的开销可能需要足够的时间,这在实践中并不重要,但我的完美主义者害怕理论上的竞争条件。在极端条件下,一些线程或内核可能严重滞后,而其他线程或内核运行得又快又高效,我可以想象,除非有锁,否则执行顺序(或内存访问)可能会被逆转。

【问题讨论】:

  • 我的问题涉及像 C++ 这样的语言,您接近机器级别,并且使用简单的 InterlockedExchange 循环实现“锁定”。我担心将变量声明为“volatile”不足以确保同步。 “原子”和“同步”之间没有区别吗?原子操作不能被拆分——如果一个变量被声明为 volatile,编译器不会重新排序对它的访问——但是 CPU 不能重新排序它们吗?尤其是当被不同的内核访问时?
  • 附加说明:在我的示例中,“sharedVariable = somevalue”用于将数据传递给 threadWhichUsesSharedVariable。 threadWhichUsesSharedVariable 只有在被父线程分配后才访问“sharedVariable”,这一点非常重要。
  • 如果重新排序对程序不可见,CPU 只能重新排序访问,因此 CPU 重新排序不应该成为问题。设计多核系统的大部分复杂性在于确保程序永远不会看到与单核系统的行为差异。

标签: multithreading locking thread-safety multicore shared-memory


【解决方案1】:

我会说您的伪代码在任何正常运行时都是安全的 多处理器系统。 C++ 编译器无法生成对 CreateThread()sharedVariable 之前收到了正确的值 除非它可以向自己证明这样做是安全的。你有保证 您的单线程代码执行等同于完全 非重新排序的线性执行路径。任何“时间扭曲”的系统 变量赋值之前的线程创建被严重破坏。

我不认为将 sharedVariable 声明为 volatile 有任何作用 在这种情况下很有用。

【讨论】:

    【解决方案2】:

    鉴于您的示例,如果您使用的是 Java,那么答案将是“否”。在 Java 中,线程不可能在赋值操作完成之前生成并读取您的值。 在其他一些语言中,这可能是另一回事。

    “在多个线程之间共享的变量(例如,对象的实例变量)具有由 Java 语言规范保证的原子分配,适用于除 long 和 double 之外的所有数据类型...如果方法仅包含单个变量访问或分配,没有必要为了线程安全而同步,也没有理由不这样做是为了提高性能。” reference

    如果您的doublelong 被声明为volatile,那么您也可以保证分配是原子操作。

    更新: 您的示例将在 C++ 中运行,就像在 Java 中一样。从理论上讲,线程生成不会在分配之前开始或完成,即使是乱序执行。

    请注意,您的示例非常具体,在任何其他情况下,建议您确保正确保护共享资源。新的 C++ 标准出现了很多原子的东西,所以你可以将你的变量声明为原子的,并且赋值操作对所有线程都是可见的,而不需要锁定。 CAS(比较和设置)是您的下一个最佳选择。

    【讨论】:

    • 感谢您的回答,但我真的是在询问 C++(或任何使您接近机器级别的语言)并且应该这么说。我将添加一条评论来澄清我的问题。
    • 谢谢 Lirik 和 Per,你们的回答都很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 2023-03-10
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多