Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 解除对不同线程中原子对象的只读非原子指针的引用安全吗?_C++_Multithreading_Pointers_Atomic - Fatal编程技术网

C++ 解除对不同线程中原子对象的只读非原子指针的引用安全吗?

C++ 解除对不同线程中原子对象的只读非原子指针的引用安全吗?,c++,multithreading,pointers,atomic,C++,Multithreading,Pointers,Atomic,如果我这样写: std::atomic<bool> *p = new std::atomic<bool>(false); // At the beginning of the program //... void thread1() { while (!(*p)) // Do something } //... void thread2() { //... *p = true;

如果我这样写:

std::atomic<bool> *p = new std::atomic<bool>(false); // At the beginning of the program  

//...  

void thread1()  
{  
    while (!(*p))  
        // Do something  
}  

//...  

void thread2()  
{  
    //...  
    *p = true;  
    //...
}  
std::atomic*p=new std::atomic(false);//在节目开始时
//...  
void thread1()
{  
而(!(*p))
//做点什么
}  
//...  
无效线程2()
{  
//...  
*p=真;
//...
}  

thread1
thread2
将同时运行。
p
的值自初始化以来从未更改。在这种情况下,解引用操作安全吗?出于性能原因,我希望避免使用原子指针

是的,它是安全的。如果没有至少一个线程修改共享变量,就无法进行数据竞争。由于两个线程都不修改
p
,因此不存在争用。

这取决于两个访问周围的内容。如果主机在设置布尔值之前写入一些数据,则从机需要一个内存屏障,以确保它不会在布尔值之前读取所述数据

也许现在您的线程正在等待这个布尔值退出,但是如果有一天您决定主线程应该(例如)将终止状态传递给从属线程,那么代码可能会中断。
如果您在6个月后回来修改这段代码,您确定您会记得从属循环之外的区域是非共享读取区域,而在主循环之前的区域是非共享写入区域吗

无论如何,布尔值必须是可变的,否则编译器可能会对其进行优化。或者更糟糕的是,你的同事的编译器可能会这样做,而你将不再编写另一段不可靠的代码

众所周知,易失性变量通常不足以实现线程同步,因为它们不实现内存屏障,如下面这个简单的示例所示:

大师:

// previous value of x = 123
x = 42;
*p = true;
从处理器上的总线逻辑:

write *p = true
write x = 42 // too late...
奴隶:

while (!*p) { /* whatever */ }
the_answer = x; // <-- boom ! the_answer = 123
(如果主机的总线写入计划混乱,则出现对称问题)

当然,很可能你永远也不会在你的台式电脑上看到这种罕见的事情,就像你可能偶然运行一个程序破坏它自己的内存而不会崩溃一样

然而,用这种漏洞百出的同步编写的软件是滴答作响的定时炸弹。在总线体系结构的主机上编译并运行它们足够长的时间,总有一天。。。轰


事实上,C++11允许创建任务,比如如果没有任务,同时只提供蹩脚的原子、互斥体和条件变量来处理同步(当然还有糟糕的未来),这大大损害了多处理器编程

同步任务(特别是工作线程)最简单、最有效的方法是让它们处理队列中的消息。这就是驱动程序和实时软件的工作原理,任何多处理器应用程序都应该如此,除非出现一些特殊的性能要求

强迫程序员用美化的标志控制多任务是愚蠢的。您需要非常清楚地了解硬件如何使用原子计数器。
C++的迂腐集团再次迫使每个人和他的狗成为另一个领域的专家,只是为了避免编写蹩脚的、不可靠的代码。p> 和往常一样,你会看到大师们带着纵容的微笑滔滔不绝地讲述他们的“良好实践”,而人们则在破碎的自制队列中愚蠢的旋转循环中消耗数百万焦耳的CPU能量,因为他们相信“不等待”同步是效率的阿尔法和欧米加

这种对表演的痴迷不是问题。“阻塞”调用只消耗了少量的可用计算能力,还有许多其他因素影响了性能,比操作系统同步原语高出几个数量级(首先,在给定处理器上没有找到任务的标准方法)

考虑一下你的线程1奴隶。访问一个原子布尔将把一把沙子扔进总线缓存齿轮中,使这个particulmar访问速度降低大约20倍。这是浪费了几十个周期。除非你的奴隶只是在循环中摆弄它的虚拟拇指,否则这几个周期将比单个循环持续的数千或数百万周期要小得多。 还有,如果你的奴隶完成了工作,而它的兄弟奴隶没有完成工作,会发生什么?它会在这个标志上无用地旋转并浪费CPU,还是阻塞任何互斥体?
消息队列就是为了解决这些问题而发明的

一个正确的操作系统调用,比如消息队列读取,可能会消耗几百个周期。那又怎样?
如果您的从线程只是为了增加3个计数器,那么是您的设计出了问题。你不启动一个线程来移动一对火柴棒,就像你不分配你的字节每字节,甚至是一个高级语言,如C++。 如果您不使用线程来咀嚼面包屑,那么您应该依赖简单且经验证的机制,如等待队列或信号量或事件(由于缺乏可移植的解决方案而选择posix或Microset),并且您不会注意到对性能的任何影响

编辑:有关系统调用开销的更多信息

基本上,呼叫等待队列需要几微秒的时间

假设您的平均工作人员处理数字的时间为10到100毫秒,系统调用开销将不受背景噪音的影响,线程终止响应将保持在可接受的范围内(<0.1秒)

我最近实现了一个并行处理测试用例。它并不能代表所有的并行处理案例,但我还是注意到了一些有趣的事情

在我的I3 Intel 2核/4 CPU@3.1 GHz上,使用每个CPU一个工作线程,我测量了增益因子(即使用1核o
do_work(&buf); // writes data to buf
done = true;   // synchronize