【发布时间】:2021-10-19 23:07:52
【问题描述】:
由于低延迟要求,我正在使用 for_each 的并行执行来识别句子(一组字符串)的意图。我之前了解到,不需要互斥锁来保护 bool 或任何其大小小于一个字节的数据类型。所以我问访问布尔成员 Tag.m_Found 是否是线程安全的?否则,我应该使用 atomic 还是 mutex?
#include <iostream>
#include <unordered_set>
#include <set>
#include <list>
#include <algorithm>
#include <execution>
struct Tag{
const std::unordered_set<std::string> m_Context;
const std::string m_Name;
volatile bool m_Found;
Tag(const std::unordered_set<std::string> context, const std::string name)
: m_Context(context)
, m_Name(name)
, m_Found(false)
{}
Tag(const Tag & tag) = delete;
Tag(Tag && tag) = default;
Tag & operator=(const Tag & tag) = delete;
};
int main(){
const std::set<std::string> input = {"hello", "my", "son"};
std::list<Tag> intentions;
intentions.emplace_back(Tag({"hello", "Hi", "morning"}, "greeting"));
intentions.emplace_back(Tag({"father", "mother", "son"}, "family"));
intentions.emplace_back(Tag({"car", "bus", "airplan"}, "transportation"));
for_each( std::execution::par
, std::begin(input)
, std::end(input)
, [& intentions](const std::string & input_element)
{
for_each( std::execution::par
, std::begin(intentions)
, std::end(intentions)
, [& input_element](Tag & intention){
if(!intention.m_Found){
intention.m_Found = intention.m_Context.find(input_element)!=intention.m_Context.end();
}
}
);
}
);
for_each( std::execution::seq
, std::begin(intentions)
, std::end(intentions)
, [](Tag & intention){
if(intention.m_Found){
std::cout<<intention.m_Name;
}
}
);
return 0;
}
【问题讨论】:
-
“我之前了解到,不需要互斥锁来保护 bool 或任何其大小小于 1 字节的数据类型。”对不起,但这是完全错误的。对任何对象的并发读/写访问需要互斥锁(或其他同步)或
std::atomic;否则你有一个未定义行为的数据竞争。bool也不例外,也不根据对象的大小,volatile也无济于事。 -
不相关:volatile 对多线程没有帮助。为什么你还有它?
-
同样,没有小于一字节的数据类型。
-
@IgorTandetnik:除了位域,对他们来说原子性情况更糟,因为每次写入都必须 RMW。
-
@NateEldredge 位字段不是类型。
标签: c++ foreach c++17 mutex atomic