multithreading - 对象地址突然变了
问题描述
class test
{
void thread1()
{
int i = 0;
while(true){
for(unsigned int k = 0;k < mLD.size(); k++ )
{
mLD[k] = i++;
}
}
}
void thread2()
{
std::cout << "thread2 address : " << &mLD << "\n";
C();
}
void B()
{
std::cout << "B address : " << &mLD << "\n";
for(unsigned int k = 0;k < mLD.size(); k++ )
{
if(mLD[k]<=25)
{
}
}
}
void C()
{
B();
std::cout << "C address : " << &mLD << "\n";
double distance = mLD[0]; // <---- segmetation fault
}
std::array<double, 360> mLD;
};
cout 结果--->
线程2地址:0x7e807660
B地址:0x7e807660
C地址:0x1010160(有时是0x7e807660)
为什么mLD的地址变了……?
即使我将 std::array 更改为std::array<std::atomic<double>360>
,结果也是一样的。
解决方案
最有可能的是,您引用的对象在调用 C 时被销毁,这表明存在同步问题。您需要延长线程引用的对象的生命周期,直到线程完成执行其例程。要做到这一点,你可以有这样的东西;
#include <thread>
#include <array>
#include <iostream>
struct foo{
void callback1(){
for(auto & elem: storage){
elem += 5;
}
}
void callback2(){
for(const auto & elem: storage){
std::cout << elem << std::endl;
}
}
std::array<double, 300> storage;
};
int main(void){
foo f;
std::thread t1 {[&f](){f.callback1();}};
std::thread t2 {[&f](){f.callback2();}};
// wait until both threads are done executing their routines
t1.join();
t2.join();
return 0;
}
foo, f 的实例存在于 main() 函数的范围内,因此它的生命周期由它定义的行定义到 main 范围的末尾。通过加入两个线程,我们阻止 main 继续进行,直到两个线程都执行完它们的回调函数,因此 f 的生命周期延长,直到回调完成。
第二个问题是,代码需要同步原语,因为存储变量在两个独立的执行路径之间共享。正确同步的最终代码如下所示;
#include <thread>
#include <array>
#include <iostream>
#include <mutex>
struct foo{
void callback1(){
// RAII style lock, which invokes .lock() upon construction, and .unlock() upon destruction
// automatically.
std::unique_lock<std::mutex> lock(mtx);
for(auto & elem: storage){
elem += 5;
}
}
void callback2(){
std::unique_lock<std::mutex> lock(mtx);
for(const auto & elem: storage){
std::cout << elem << std::endl;
}
}
std::array<double, 300> storage;
// non-reentrant mutex
mutable std::mutex mtx;
};
int main(void){
foo f;
std::thread t1 {[&f](){f.callback1();}};
std::thread t2 {[&f](){f.callback2();}};
// wait until both threads are done executing their routines
t1.join();
t2.join();
return 0;
}
推荐阅读
- rabbitmq - 直接发布到队列时 RabbitMQ DLX 不起作用
- javascript - 对布局更改做出本机反应(监听视图位置)
- python - 在多个文件中编写同一行的简洁方法 - Python
- java - 检查 String 变量是否被修改,如果不是 Toast。但是吐司总是出现
- java - Java:生产者-消费者两个线程停止工作,冻结
- sql-server - 插入时如何将行值增加1
- fortran - 如何在这里修复不平衡的括号?
- string - 如何在powershell中剪切这些字符串中的子字符串?
- aws-lambda - 使用无服务器框架部署 lambda 函数时出错
- database - 如何解决 MongoDB 查询括号错误?