【问题标题】:Can I safely write a constant value to a variable from multiple threads in C++?我可以安全地将常量值从 C++ 中的多个线程写入变量吗?
【发布时间】:2015-01-28 13:40:09
【问题描述】:

特别是,我想设置一个函数指针的值。为简单起见,我想从多个线程中多次执行此操作,但始终以这样的简单方式:

typedef void (*F)();
F f = 0;

void foo()
{
}

// called many times from multiple threads
void set()
{
    f = &foo;
}

int main()
{
    set();  // also other threads can invoke it at any time
    f();
    return 0;
}

因此,函数指针最初为 NULL,然后在第一次执行代码时变为 &foo。我想知道是否由于任何非原子写入操作,函数指针可能会被破坏。

保证设置后第一次读取。

编辑:我澄清一下:

  1. 我使用函数指针的主要原因是为了消除模块之间的一些依赖关系。这是一个大型实际项目的一小部分。我真的不能直接调用'foo'。
  2. 我知道如何编程,我不需要关于互斥锁之类的基本信息。我的问题是没有互斥锁是否安全。
  3. 在代码中保证没有其他线程将指针设置为 &foo 以外的任何东西。

【问题讨论】:

  • 你能发布一些现实的,但最少的代码吗?
  • 即使它是原子的,多个线程更改函数指针意味着调用该函数的人不知道实际会调用什么。
  • @juanchopanza:我扩展了示例代码,让它更完整。
  • @Chad:关键是无论谁调用它都可以确定,它早先被设置为“&foo”。
  • 除非另一个线程在第一个线程使用它之前也设置它&bar

标签: c++ thread-safety


【解决方案1】:

您是否考虑过使用std::mutexstd::lock_guard 来强制线程安全?

例如

{
    std::lock_guard<std::mutex> lg(my_mutex);
    f = &foo;
    // then use f to perform your operation
}

在右大括号之后,lock_guard 超出范围并解锁您的mutex。这意味着任何设置 f 的人都可以安全地使用该函数指针,因为知道另一个线程在设置它和尝试使用它之间没有更改函数指针。

【讨论】:

  • 是的,我知道这种可能性,但我想知道,如果没有它,这个写入是否安全。我试图不使用任何互斥体来减少项目中的依赖关系。
  • @MichalCzardybon 要专门回答这个问题,no, a pointer assignment is not necessarily thread safe
  • 但我说的是分配的值始终相同的情况。因此,即使两个线程同时写入,它们也会写入相同的值。我无法想象这会如何导致任何问题。顺便提一句。 f = &foo 被转换为单个 'mov' 指令。
  • @MichalCzardybon 如果函数指针始终是同一个函数,为什么还要在这里使用它?具体来说,如果你可以从任何地方调用set,然后再调用f,那么你肯定可以从任何地方调用foo,不是吗?
  • @MichalCzardybon 好的。使用std::mutex。这是大声喊叫的 c++ 标准库。这不是依赖...
【解决方案2】:

标准说您的代码调用了未定义的行为。但是在您的特定情况下,即使用您的特定编译器和体系结构,您的代码实际上可能没有问题。所以,从理论上讲,你的代码是不行的。从实际的角度来看,答案取决于您的具体情况,绝不是普遍的。就个人而言,我建议将F f = 0; 替换为std::atomic&lt;F&gt; f(0);,以保证代码在所有情况下都正常。

只是为了说明您的代码中断的情况:实现可能会选择在每次写入操作之前清除目标。这样的实现是合法的并且符合标准,虽然不一定获奖:)

【讨论】:

  • 这正是我最初的想法。我只是不确定我是否错过了什么。我应该仅仅因为你的想法和我的想法一样就接受你的问题吗? ;-)
  • @MichalCzardybon 我很高兴我们也这么认为。如果您能接受我的回答,我将不胜感激:)
  • 我接受,但如果您也提供一些引用来证明您的陈述是正确的,我将不胜感激。在此之前接受只是因为你给了我我想听到的答案。
【解决方案3】:

我认为这更像是一个线程同步问题,而不是与 c++ 相关的问题。 您的问题的答案是,是的,您可以在 c++ 中安全地将值写入变量/指针(不确定常量是什么意思;在我看来,您只是想分配一个函数指针),您只需使用互斥,这样线程就不会在您不希望它们覆盖时覆盖该值

根据您最终想要实现的目标,您可能需要多个互斥体(即,如果您想确保线程分配函数指针的特定顺序),但这绝对是安全的方法。

【讨论】:

  • 我的问题是:没有互斥锁是否安全。
  • 不,不是;你永远不知道线程什么时候会被刷掉,所以代码很可能会崩溃。想象一下,如果第一个线程在执行它分配函数指针的方法时被刷出,而第二个线程进入并覆盖函数指针会发生什么。
  • 但是所有可能的赋值都写出完全相同的值。这就是这个问题的重点。两个线程同时写入 &foo 后,我们还能得到除 &foo 之外的任何值吗?
  • 如果两个线程写相同的东西,我认为你不能得到不同的值,但这高度依赖于调度程序和编译器。但如果你这样说,听起来更像是一个理论问题,没有实际适用性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多