C++ 如何确保两个线程中的两个类编写相同的变量是线程安全的?
我有两个类同时在两个线程中运行,比如classC++ 如何确保两个线程中的两个类编写相同的变量是线程安全的?,c++,multithreading,mutex,C++,Multithreading,Mutex,我有两个类同时在两个线程中运行,比如classA和classB,A正在从一些API收集数据,并不断将更新的数据推送到一个无序的映射中,如B->m。同时,B正在使用数据创建自定义类Bar,代码如下: 类A: if(m.size() > 0){ //mtx.lock(); lock = B->lock; if(lock == false){ lock = true; B->m = m; lock = false; } m.clear(); //mtx.
A
和classB
,A
正在从一些API收集数据,并不断将更新的数据推送到一个无序的映射中,如B->m
。同时,B
正在使用数据创建自定义类Bar
,代码如下:
类A
:
if(m.size() > 0){
//mtx.lock();
lock = B->lock;
if(lock == false){
lock = true;
B->m = m;
lock = false;
}
m.clear();
//mtx.unlock();
}
while(true){
if(m.size() > 0){
//mtx.lock();
if(lock == false){
lock = true;
for (auto it : m) {
std::string symbol = it.first;
std::vector<double> v = it.second;
Bar b;
b.open = v[0];
b.high = v[1];
bars.push_back(b);
}
m.clear();
lock = false;
}
//mtx.unlock();
}}
类B
:
if(m.size() > 0){
//mtx.lock();
lock = B->lock;
if(lock == false){
lock = true;
B->m = m;
lock = false;
}
m.clear();
//mtx.unlock();
}
while(true){
if(m.size() > 0){
//mtx.lock();
if(lock == false){
lock = true;
for (auto it : m) {
std::string symbol = it.first;
std::vector<double> v = it.second;
Bar b;
b.open = v[0];
b.high = v[1];
bars.push_back(b);
}
m.clear();
lock = false;
}
//mtx.unlock();
}}
while(true){
如果(m.size()>0){
//mtx.lock();
if(lock==false){
lock=true;
用于(自动it:m){
std::string symbol=it.first;
std::vector v=it.second;
b栏;
b、 开路=v[0];
b、 高=v[1];
杆。推回(b);
}
m、 清除();
锁=假;
}
//mtx.unlock();
}}
从这里可以看出,我曾尝试使用一个名为lock
的布尔值手动实现互斥锁,当我编译时,它有时会结束,有时会出现seg错误,我认为这是因为边缘情况:当我在classB
中将lock
设置为true
时,classa
刚刚跳过了if(lock==false)
和B
正在读取由A
更改的数据。我的问题是,如何避免这种情况发生 手动互斥实现将无法工作(至少不容易)。例如,从编译器的角度来看
lock = strategy->lock;
if(lock == false){
lock = true;
B->m = m;
lock = false;
}
可以重新调整到这个位置
lock = strategy->lock;
if(lock == false){
B->m = m;
}
因为单线程结果(如果您不告诉它,这是编译器的默认观点)是完全相同的
还有其他可能失败的原因,例如部分对象填充。通常是复杂的东西
因此,您必须使用正在使用的库提供给您的某些同步对象。对于C++11及更高版本,您只需使用:
#包括
std::mutex my_mutex;
...
//一些代码
{
//锁资源
std::锁定保护lg(我的互斥);
B->m=m;
}
//自动释放锁并继续执行
手动互斥实现将无法工作(至少不容易实现)。例如,从编译器的角度来看
lock = strategy->lock;
if(lock == false){
lock = true;
B->m = m;
lock = false;
}
可以重新调整到这个位置
lock = strategy->lock;
if(lock == false){
B->m = m;
}
因为单线程结果(如果您不告诉它,这是编译器的默认观点)是完全相同的
还有其他可能失败的原因,例如部分对象填充。通常是复杂的东西
因此,您必须使用正在使用的库提供给您的某些同步对象。对于C++11及更高版本,您只需使用:
#包括
std::mutex my_mutex;
...
//一些代码
{
//锁资源
std::锁定保护lg(我的互斥);
B->m=m;
}
//自动释放锁并继续执行
您需要std::mutex和std::condition\u变量
std::mutex
用于保护代码不受未定义行为的影响,以及std::condition_variable
用于通知工作线程需要完成一些工作
如果您确实想实现互斥,那么请确保您使用的是原子类型,例如std::atomic_flag
,std::atomic
等
为自己实现一个“线程安全”容器是解决您的问题的一个简单选择,它将类似于(尚未测试,只是为了查看):
#包括
#包括
#包括
模板
类容器{
公众:
bool Get(常量键和键、值和值){
标准:锁紧保护装置(mtx);
auto ite=mp_.find(键);
如果(ite==mp_u2;end())
返回false;
值=标准::移动(现场->秒);
mp_.擦除(ite);
返回true;
}
模板
无效插入(常量键和键、值类型和值){
标准:锁紧保护装置(mtx);
mp_u[key]=std::forward(值);
}
私人:
std::无序地图mp;
std::互斥mtx;
};
在实现并发算法时,有很多事情需要注意,我建议您首先阅读一些关于这个主题的书籍(不要担心,无论如何,您都会以艰苦的方式学习它们)。“C++并发运行”是一个良好的开端。您需要std::mutex和std::condition\u变量
std::mutex
用于保护代码不受未定义行为的影响,以及std::condition_variable
用于通知工作线程需要完成一些工作
如果您确实想实现互斥,那么请确保您使用的是原子类型,例如std::atomic_flag
,std::atomic
等
为自己实现一个“线程安全”容器是解决您的问题的一个简单选择,它将类似于(尚未测试,只是为了查看):
#包括
#包括
#包括
模板
类容器{
公众:
bool Get(常量键和键、值和值){
标准:锁紧保护装置(mtx);
auto ite=mp_.find(键);
如果(ite==mp_u2;end())
返回false;
值=标准::移动(现场->秒);
mp_.擦除(ite);
返回true;
}
模板
无效插入(常量键和键、值类型和值){
标准:锁紧保护装置(mtx);
mp_u[key]=std::forward(值);
}
私人:
std::无序地图mp;
std::互斥mtx;
};
在实现并发算法时,有很多事情需要注意,我建议您首先阅读一些关于这个主题的书籍(不要担心,无论如何,您都会以艰苦的方式学习它们)。“C++并发运行”是一个良好的开端。手动互斥实现将无法工作。别这样。从pthread或std::mutex
使用适当的互斥对象(如果是C++1x)。@如果使用std::mutex,我应该将mutex.lock()放在哪里?请参阅上面的注释代码,我尝试了它,但没有成功,因为它在两个类中是互斥的。不要使用<