- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
下面的代码显示了两种通过原子标志获取共享状态的方法。读取器线程调用 poll1()
或 poll2()
来检查写入器是否已发出标志。
投票选项#1:
bool poll1() {
return (flag.load(std::memory_order_acquire) == 1);
}
投票选项#2:
bool poll2() {
int snapshot = flag.load(std::memory_order_relaxed);
if (snapshot == 1) {
std::atomic_thread_fence(std::memory_order_acquire);
return true;
}
return false;
}
请注意,选项 #1 是 presented in an earlier question ,选项 #2 类似于 example code at cppreference.com .
假设读者同意仅在 poll
函数返回 true
时检查共享状态,那么这两个 poll
函数是否正确且等价?
选项 #2 是否有标准名称?
每个选项的优点和缺点是什么?
选项 #2 在实践中可能更有效吗?是否有可能降低效率?
这是一个完整的工作示例:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
int x; // regular variable, could be a complex data structure
std::atomic<int> flag { 0 };
void writer_thread() {
x = 42;
// release value x to reader thread
flag.store(1, std::memory_order_release);
}
bool poll1() {
return (flag.load(std::memory_order_acquire) == 1);
}
bool poll2() {
int snapshot = flag.load(std::memory_order_relaxed);
if (snapshot == 1) {
std::atomic_thread_fence(std::memory_order_acquire);
return true;
}
return false;
}
int main() {
x = 0;
std::thread t(writer_thread);
// "reader thread" ...
// sleep-wait is just for the test.
// production code calls poll() at specific points
while (!poll2()) // poll1() or poll2() here
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << x << std::endl;
t.join();
}
最佳答案
我想我可以回答你的大部分问题。
这两个选项当然是正确的,但它们并不完全等同,因为独立围栏的适用范围略广(它们在你想要完成的事情方面是等价的,但独立围栏在技术上可以适用于还有其他事情——想象一下如果这段代码是内联的)。 this post by Jeff Preshing 中解释了独立围栏与存储/获取围栏有何不同的示例。 .
据我所知,选项 #2 中的先检查后围栏模式没有名称。不过,这并不少见。
就性能而言,在 x64 (Linux) 上使用我的 g++ 4.8.1,两个选项生成的程序集归结为单个加载指令。这不足为奇,因为 x86(-64) 加载和存储无论如何都在硬件级别具有获取和释放语义(x86 以其非常强大的内存模型而闻名)。
但是,对于 ARM,内存屏障编译为实际的单个指令,会产生以下输出(使用 gcc.godbolt.com 和 -O3 -DNDEBUG
):
对于 while (!poll1());
:
.L25:
ldr r0, [r2]
movw r3, #:lower16:.LANCHOR0
dmb sy
movt r3, #:upper16:.LANCHOR0
cmp r0, #1
bne .L25
对于 while (!poll2());
:
.L29:
ldr r0, [r2]
movw r3, #:lower16:.LANCHOR0
movt r3, #:upper16:.LANCHOR0
cmp r0, #1
bne .L29
dmb sy
您可以看到,唯一的区别是同步指令 (dmb
) 的放置位置——在 poll1
的循环内,在 poll2 的循环之后
。所以 poll2
在这种真实情况下确实更有效 :-)(但请进一步阅读,了解为什么如果在循环中调用它们以阻塞直到标志更改,这可能无关紧要。)
对于 ARM64,输出是不同的,因为有内置障碍的特殊加载/存储指令(ldar
-> load-acquire)。
对于 while (!poll1());
:
.L16:
ldar w0, [x1]
cmp w0, 1
bne .L16
对于 while (!poll2());
:
.L24:
ldr w0, [x1]
cmp w0, 1
bne .L24
dmb ishld
同样,poll2
导致一个循环,内部没有障碍,外部有一个障碍,而 poll1
每次通过时都会有一个障碍。
现在,实际上哪个性能更好需要运行基准测试,不幸的是我没有相应的设置。 poll1
和 poll2
,与直觉相反,在这种情况下最终可能同样有效,因为花费额外的时间等待内存效应在循环内传播可能实际上并没有浪费时间如果标志变量是无论如何都需要传播的那些效果之一(即,即使对 poll1
的单个(内联)调用比对 轮询 2
)。当然,这是假设一个等待标志更改的循环——对 poll1
的单独调用 do 比对 poll2
的单独调用需要更多的工作.
所以,我认为总的来说,可以肯定地说 poll2
的效率永远不会比 poll1
低得多,而且通常会更快,只要编译器可以消除内联时的分支(这似乎至少是这三种流行架构的情况)。
我的(略有不同的)测试代码供引用:
#include <atomic>
#include <thread>
#include <cstdio>
int sharedState;
std::atomic<int> flag(0);
bool poll1() {
return (flag.load(std::memory_order_acquire) == 1);
}
bool poll2() {
int snapshot = flag.load(std::memory_order_relaxed);
if (snapshot == 1) {
std::atomic_thread_fence(std::memory_order_acquire);
return true;
}
return false;
}
void __attribute__((noinline)) threadFunc()
{
while (!poll2());
std::printf("%d\n", sharedState);
}
int main(int argc, char** argv)
{
std::thread t(threadFunc);
sharedState = argc;
flag.store(1, std::memory_order_release);
t.join();
return 0;
}
关于c++ - 按需条件 std::atomic_thread_fence 获取的优缺点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35271393/
我正在努力处理查询的 WHERE 部分。查询本身包含一个基于两个表中都存在的 ID 的 LEFT JOIN。但是,我要求 where 语句仅返回其中一列中存在的最大单个结果。目前我返回连接中的所有值,
我有这个代码来改变文件系统的大小。问题是,即使满足 if 条件,它也不会进入 if 条件,而我根本没有检查 if 条件。它直接进入 else 条件。 运行代码后的结果 post-install-ray
假设我有一个包含 2 列的 Excel 表格:单元格 A1 到 A10 中的日期和 B1 到 B10 中的值。 我想对五月日期的所有值求和。我有3种可能性: {=SUM((MONTH(A1:A10)=
伪代码: SELECT * FROM 'table' WHERE ('date' row.date 或 ,我们在Stack Overflow上找到一个类似的问题: https://stackove
我有下面这行代码做一个简单的查询 if ($this->fulfilled) $criteria->addCondition('fulfilled ' . (($this->fulfilled
如果在数据库中找到用户输入的键,我将尝试显示“表”中的数据。目前我已将其设置为让数据库检查 key 是否存在,如下所示: //Select all from table if a key entry
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 5 年前。 Improve th
在MYSQL中可以吗 一共有三个表 任务(task_id、task_status、...) tasks_assigned_to(ta_id、task_id、user_id) task_suggeste
我想先根据用户的状态然后根据用户名来排序我的 sql 请求。该状态由 user_type 列设置: 1=活跃,2=不活跃,3=创始人。 我会使用此请求来执行此操作,但它不起作用,因为我想在“活跃”成员
下面两个函数中最专业的代码风格是什么? 如果函数变得更复杂和更大,例如有 20 个检查怎么办? 注意:每次检查后我都需要做一些事情,所以我不能将所有内容连接到一个 if 语句中,例如: if (veh
我在 C# 项目中使用 EntityFramework 6.1.3 和 SQL Server。我有两个查询,基本上应该执行相同的操作。 1. Exams.GroupBy(x=>x.SubjectID)
我试图在 case when 语句中放入两个条件,但我在 postgresql 中遇到语法错误 case when condition 1 and condition 2 then X else Y
我正在构建一个连接多个表的查询,一个表 prodRecipe 将包含某些行的数据,但不是全部,但是 tmp_inv1 将包含所有行的计数信息。问题是,tmp_inv1.count 取决于某个项目是否在
我有一个涉及 couples of rows which have a less-than-2-hours time-difference 的查询(~0.08333 天): SELECT mt1.*,
我有一个包含许多这样的 OR 条件的代码(工作正常)来检查其中一个值是否为空,然后我们抛出一条错误消息(所有这些都必须填写) } elsif ( !$params{'account'}
我有一个名为 spGetOrders 的存储过程,它接受一些参数:@startdate 和 @enddate。这将查询“订单”表。表中的一列称为“ClosedDate”。如果订单尚未关闭,则此列将保留
在代码中,注释部分是我需要解决的问题...有没有办法在 LINQ 中编写这样的查询?我需要这个,因为我需要根据状态进行排序。 var result = ( from contact in d
我正在尝试创建一个允许省略参数的存储过程,但如果提供了参数,则进行 AND 操作: CREATE PROCEDURE MyProcedure @LastName Varchar(30)
我正在寻找一种方法来过滤我的主机文件中的新 IP 地址。我创建了一个脚本,每次我用来自矩阵企业管理器的数据调用它时都会更新我的主机文件。它工作正常。但是我必须找到一个解决方案,只允许更新 10.XX.
所以我正在做一种 slider ,当它完全向下时隐藏向下按钮,反之亦然,当向上按钮隐藏时,我遇到了问题。 var amount = $('slide').attr('number'); $('span
我是一名优秀的程序员,十分优秀!