布尔成员的C++多线程访问
C++ multithreaded access of boolean member
由于低延迟要求,我使用 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;
}
问题是如果添加“std::mutex m_Found_access;”或制作“atomic_bool m_Found;”默认的移动构造函数被删除,所以我需要为标签定义一个移动构造函数。并且 m_Found 应该只设置为 true 以避免竞争条件(如@Nate Eldredge所述)。代码变为:
#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;
std::atomic_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 & operator=(const Tag & tag) = delete;
Tag(Tag && tag) : m_Context(std::move(tag.m_Context))
, m_Name(std::move(tag.m_Name))
, m_Found(static_cast< bool >(tag.m_Found))
{}
};
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){
if(intention.m_Context.find(input_element)!=intention.m_Context.end()){
intention.m_Found = true;
}
}
}
);
}
);
for_each( std::execution::seq
, std::begin(intentions)
, std::end(intentions)
, [](Tag & intention){
if(intention.m_Found){
std::cout<<intention.m_Name;
}
}
);
return 0;
}
由于低延迟要求,我使用 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;
}
问题是如果添加“std::mutex m_Found_access;”或制作“atomic_bool m_Found;”默认的移动构造函数被删除,所以我需要为标签定义一个移动构造函数。并且 m_Found 应该只设置为 true 以避免竞争条件(如@Nate Eldredge所述)。代码变为:
#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;
std::atomic_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 & operator=(const Tag & tag) = delete;
Tag(Tag && tag) : m_Context(std::move(tag.m_Context))
, m_Name(std::move(tag.m_Name))
, m_Found(static_cast< bool >(tag.m_Found))
{}
};
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){
if(intention.m_Context.find(input_element)!=intention.m_Context.end()){
intention.m_Found = true;
}
}
}
);
}
);
for_each( std::execution::seq
, std::begin(intentions)
, std::end(intentions)
, [](Tag & intention){
if(intention.m_Found){
std::cout<<intention.m_Name;
}
}
);
return 0;
}