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

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

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

正常代码

#include 
#include 
#include 

// 线程函数,用于执行具体的任务
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 
#include 
#include 

// 线程函数,用于执行具体的任务
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;
}

编译成功,但是运行失败。
运行结果:
C++多线程场景中的变量提前释放导致栈内存异常_第1张图片
上面std::thread funThread(&num{fun(num);});,采用引用传递,并且void fun(int& param)中也采用引用入参的形式。此时可能就会产生内存泄露。

因为传入参数num是一个局部参数,我们在fun中修改或读取param时,可能num已经被释放掉了,这时候修改或者读取param就会发生内存错误,其实这里是栈内存异常。这是非常危险的,因为栈内存可能会造成无法估量的问题。

优化代码

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

#include 
#include 
#include 

// 线程函数,用于执行具体的任务
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;
}

你可能感兴趣的:(C++,c++,算法,jvm)