【发布时间】:2017-06-23 04:14:05
【问题描述】:
如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 保证不会仍在运行。
否则第一次初始化这样的变量 控制通过它的声明;考虑这样一个变量 在其初始化完成时初始化。 [...]如果控制同时进入声明,而 变量正在初始化,并发执行应等待 用于完成初始化。 [...]
我错了吗?这是一个巨大的缺陷吗?是否已知此用例会从裂缝中溜走,以便 helgrind 报告可能的竞赛?
【问题讨论】:
-
如果你在初始化过程中得到汇编程序,它看起来好像正在使用锁吗?
-
读取
local_key.value周围肯定没有任何锁定。至于初始化,是的,它被__cxa_guard_acquire和__cxa_guard_release括起来
标签: c++ thread-safety valgrind