gpt4 book ai didi

c++ - helgrind 报告了使用单例和它的构造函数之间可能存在的竞争

转载 作者:太空宇宙 更新时间:2023-11-04 12:59:49 24 4
gpt4 key购买 nike

如前所述there , Meyer 的单例在 C++11 中是线程安全的。

所以我希望这段代码没问题:

#include <stdio.h>
#include <pthread.h>

struct key_type {
int value;
key_type() : value(0) { }
};


void * thread1(void*) {
static key_type local_key;
printf("thread has key %d\n", local_key.value);
return NULL;
}

int main()
{
pthread_t t[2];
pthread_create(&t[0], NULL, thread1, NULL);
pthread_create(&t[1], NULL, thread1, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
}

(故意过度简化代码,我知道我可以简单地进行零初始化。)

我正在使用 g++-7.1.0 进行编译。 Helgrind (valgrind-3.12.0) 报告在读取 local_key.value 和设置 value 的 ctor 之间可能数据竞争。

==29036== Possible data race during read of size 4 at 0x601058 by thread #3
==29036== Locks held: none
==29036== at 0x4006EA: thread1(void*) (datarace-simplest.cpp:12)
==29036== by 0x4C32D06: mythread_wrapper (hg_intercepts.c:389)
==29036== by 0x4E45493: start_thread (pthread_create.c:333)
==29036== by 0x59DEAFE: clone (clone.S:97)
==29036==
==29036== This conflicts with a previous write of size 4 by thread #2
==29036== Locks held: none
==29036== at 0x400780: key_type::key_type() (datarace-simplest.cpp:6)
==29036== by 0x4006DF: thread1(void*) (datarace-simplest.cpp:11)
==29036== by 0x4C32D06: mythread_wrapper (hg_intercepts.c:389)
==29036== by 0x4E45493: start_thread (pthread_create.c:333)
==29036== by 0x59DEAFE: clone (clone.S:97)
==29036== Address 0x601058 is 0 bytes inside data symbol "_ZZ7thread1PvE9local_key"

我认为 c++11 标准(§6.7)保证 local_key 一劳永逸地初始化,因此进一步的访问处理变量,其 ctor 保证不会仍在运行.

Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. [...] If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. [...]

我错了吗?这是一个 helgrind 缺陷吗?这个用例是否已知会从裂缝中溜走,以至于 helgrind 报告可能竞争?

最佳答案

反汇编函数 thread1,我看到调用了 __cxa_guard_acquire和 __cxa_guard_release,我认为我们可以合理地假设它是什么保护构造函数。但是,此类调用不会被拦截由 helgrind,因此,helgrind 没有观察到任何同步。这是 Valgrind/helgrind 中的一个错误/弱点,值得在 valgrind bugzilla 上提交错误。但是请注意,快速阅读代码,对 __cxa_guard_acquire 和 __cxa_guard_release 的调用似乎不直接匹配一对锁定/解锁:看起来代码可能只调用获取,然后不调用释放:

   00x000000000040077e <+24>:   mov    $0x600d00,%edi
0x0000000000400783 <+29>: callq 0x400610 <__cxa_guard_acquire@plt>
0x0000000000400788 <+34>: test %eax,%eax
0x000000000040078a <+36>: setne %al
0x000000000040078d <+39>: test %al,%al
0x000000000040078f <+41>: je 0x4007a5 <thread1(void*)+63>
0x0000000000400791 <+43>: mov $0x600d08,%edi
0x0000000000400796 <+48>: callq 0x40082e <key_type::key_type()>
0x000000000040079b <+53>: mov $0x600d00,%edi
0x00000000004007a0 <+58>: callq 0x400650 <__cxa_guard_release@plt>
0x00000000004007a5 <+63>: mov 0x20055d(%rip),%eax # 0x600d08 <_ZZ7thread1PvE9local_key>

稍微调试了一下,守卫好像就在前面local_key,并在构造对象后设置为 1。我不太清楚 __cxa_guard_release 必须做什么。需要更多阅读 c++ 运行时库代码,我想了解 helgrind 如何(可能)被指示那里发生了什么。

另请注意,valgrind drd 工具同样存在相同的错误/弱点。

关于c++ - helgrind 报告了使用单例和它的构造函数之间可能存在的竞争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44698412/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com