C++多线程场景中的变量提前释放导致栈内存异常

简介: C++多线程场景中的变量提前释放导致栈内存异常

多线程场景中的栈内存异常

在子线程中尝试使用当前函数的资源,是非常危险的,但是C++支持这么做。因此C++这么做可能会造成栈内存异常。

正常代码

#include <iostream>
#include <thread>
#include <windows.h>
// 线程函数,用于执行具体的任务
void fun(int param)
{
  std::cout << __FUNCTION__ << " param:" << param << std::endl;
  Sleep(3000);
  param = 1;
  std::cout << __FUNCTION__ << " param:" << param << std::endl;
}
// 线程函数,用于执行具体的任务
void threadFunction() {
  // 在这里执行线程的具体任务
  int num = 2;
  //在函数中还启动了一个线程
  std::thread funThread([num]()
    {
      fun(num);
    });
  funThread.detach();
}
int main() {
  const int numThreads = 3;
  std::thread threads[numThreads];
  // 创建并启动多个线程
  for (int i = 0; i < numThreads; ++i) {
    threads[i] = std::thread(threadFunction);
  }
  //等待所有线程执行完毕
  for (int i = 0; i < numThreads; ++i) {
    threads[i].join();
  }
  Sleep(1000);
  std::cout << "All threads have completed." << std::endl;
  return 0;
}

上述是一个正常的多线程代码。

异常代码

但是如果将其中多线程传参设置为引用传递,可能就会造成栈内存异常了,如下所示:

#include <iostream>
#include <thread>
#include <windows.h>
// 线程函数,用于执行具体的任务
void fun(int& param)//传参修改为引用传递
{
  std::cout << __FUNCTION__ << " param:" << param << std::endl;
  Sleep(3000);
  param = 1;
  std::cout << __FUNCTION__ << " param:" << param << std::endl;
}
// 线程函数,用于执行具体的任务
void threadFunction() {
  // 在这里执行线程的具体任务
  int num = 2;
  //在函数中还启动了一个线程,传参为引用
  std::thread funThread([&num]()
    {
      fun(num);
    });
  funThread.detach();
}
int main() {
  const int numThreads = 3;
  std::thread threads[numThreads];
  // 创建并启动多个线程
  for (int i = 0; i < numThreads; ++i) {
    threads[i] = std::thread(threadFunction);
  }
  //等待所有线程执行完毕
  for (int i = 0; i < numThreads; ++i) {
    threads[i].join();
  }
  Sleep(1000);
  std::cout << "All threads have completed." << std::endl;
  return 0;
}

编译成功,但是运行失败。

运行结果:

上面std::thread funThread(&num{fun(num);});,采用引用传递,并且void fun(int& param)中也采用引用入参的形式。此时可能就会产生内存异常。

因为传入参数num是一个局部参数,我们在fun中修改或读取param时,可能num已经被释放掉了,这时候修改或者读取param就会发生内存错误,其实这里是栈内存异常。这是非常危险的,因为栈内存可能会造成无法估量的问题。本代码中只有这一个作业线程,所以就在这里报错了,所以就在任务函数中崩掉了。但是因为代码中可能还可以读取修改参数param,而导致其他线程中的异常,这种问题往往很难定位。

优化代码

当然我们用引用传递的好处是可以避免临时变量的产生,但变量是复杂对象时,还是可以很大程度减少内存消耗。虽然不能用引用,但是我们可以使用std::move来实现变量所有权的转移,也可以减少临时变量的拷贝。

#include <iostream>
#include <thread>
#include <windows.h>
// 线程函数,用于执行具体的任务
void fun(int&& param)//右值传参
{
  std::cout << __FUNCTION__ << " param:" << param << std::endl;
  Sleep(3000);
  param = 1;
  std::cout << __FUNCTION__ << " param:" << param << std::endl;
}
// 线程函数,用于执行具体的任务
void threadFunction() {
  // 在这里执行线程的具体任务
  int num = 2;
  //在函数中还启动了一个线程
  std::thread funThread(fun, std::move(num));//使用move传入右值
  funThread.detach();
}
int main() {
  const int numThreads = 3;
  std::thread threads[numThreads];
  // 创建并启动多个线程
  for (int i = 0; i < numThreads; ++i) {
    threads[i] = std::thread(threadFunction);
  }
  //等待所有线程执行完毕
  for (int i = 0; i < numThreads; ++i) {
    threads[i].join();
  }
  Sleep(1000);
  std::cout << "All threads have completed." << std::endl;
  return 0;
}


目录
相关文章
|
23天前
|
算法 编译器 C语言
【C++ 异常】C++ 标准库异常类及其应用
【C++ 异常】C++ 标准库异常类及其应用
17 0
|
24天前
|
存储 C++ 容器
学会在 C++ 中使用变量:从定义到实践
C++中的变量是数据容器,包括`int`、`double`、`char`、`string`和`bool`等类型。声明变量时指定类型和名称,如`int myNum = 15;`。`cout`与`&lt;&lt;`用于显示变量值。常量用`const`声明,值不可变。变量名应唯一,遵循特定命名规则,常量声明时需立即赋值。
112 1
|
24天前
|
安全 算法 C++
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误(三)
【C++ 异常 】深入了解C++ 异常机制中的 terminate()处理 避免不必要的错误
47 0
|
24天前
|
数据可视化 关系型数据库 编译器
【C/C++ 单线程性能分析工具 Gprof】 GNU的C/C++ 性能分析工具 Gprof 使用全面指南
【C/C++ 单线程性能分析工具 Gprof】 GNU的C/C++ 性能分析工具 Gprof 使用全面指南
99 2
|
22天前
|
存储 算法 Java
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
69 0
|
24天前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
63 0
|
22天前
|
安全 程序员 C++
【C++ 基本知识】现代C++内存管理:探究std::make_系列函数的力量
【C++ 基本知识】现代C++内存管理:探究std::make_系列函数的力量
97 0
|
22天前
|
Linux API C++
【C++ 线程包裹类设计】跨平台C++线程包装类:属性设置与平台差异的全面探讨
【C++ 线程包裹类设计】跨平台C++线程包装类:属性设置与平台差异的全面探讨
50 2
|
23天前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
68 0
|
23天前
|
算法 Java C++
【C/C++ 内存知识扩展】内存不足的可能性分析
【C/C++ 内存知识扩展】内存不足的可能性分析
12 0

相关实验场景

更多