多个线程一起创建时,某些线程的线程函数参数被篡改

博客讨论了在C程序中使用pthread_create创建线程时遇到的问题,由于在for循环中定义并传递线程参数,导致线程0和线程2无法成功创建。分析指出,临时变量可能在线程函数调用前被销毁,造成野指针问题。解决方案是使用全局变量和结构体数组确保线程参数的持久性。修复后的代码避免了临时变量的影响,成功创建了所有预期线程。
摘要由CSDN通过智能技术生成

公司某个程序需要在启动时创建多个线程,我们使用for循环来一起创建,结果某些期望的线程一直创建不成功!
关键代码如下:

enum en_TaskId
{
	TaskId_0 = 0,
	TaskId_1,
	TaskId_2,
	TaskId_3,
	TaskId_4,
	TaskNum = 5
};

// 创建 5 个线程
void create_thread()
{
	pthread_t thread;
	
	for(u32 dwIndex = 0; dwIndex < TaskNum; dwIndex++)
	{
		TThreadInfo tThreadInfo = { 0 };
		tThreadInfo.pcTask = this;
		tThreadInfo.dwIndex = dwIndex;
		Print("[start] pthread_create() dwIndex: %d\r\n", tThreadInfo.dwIndex);
		pthread_create(&thread, NULL, thread_func,(void*)&tThreadInfo);
		Print("[end] pthread_create() dwIndex: %d\r\n", tThreadInfo.dwIndex);
		usleep(10000);
	}
	Print("create end\r\n");
}


// 线程函数
static void* thread_func(void* arg0)
{
	TThreadInfo* pThis = (TThreadInfo*)arg0;
	u32 nIndex = pThis->dwIndex;
	Print("task create callback: 0x%x, idx: %d\n", pThis, nIndex);
	pThis->pcTask->RealTaskProcess(nIndex);
}

结果打印如下:

[start] pthread_create() dwIndex: 0
[end] pthread_create() dwIndex: 0
task create callback: 0xb0edd8d0, idx: 1

[start] pthread_create() dwIndex: 1
task create callback: 0xb0edd8d0, idx: 1
[end] pthread_create() dwIndex: 1

[start] pthread_create() dwIndex: 2
[end] pthread_create() dwIndex: 2
task create callback: 0xb0edd8d0, idx: 3

[start] pthread_create() dwIndex: 3
[end] pthread_create() dwIndex: 3
task create callback: 0xb0edd8d0, idx: 4

[start] pthread_create() dwIndex: 4
[end] pthread_create() dwIndex: 4
task create callback: 0xb0edd8d0, idx: 4

create end

由上述打印可知:期待的 线程0 和 线程2 根本没有创建出来,

// 创建 5 个线程
void create_thread()
{
	pthread_t thread;
	
	for(u32 dwIndex = 0; dwIndex < TaskNum; dwIndex++)
	{
		TThreadInfo tThreadInfo = { 0 };
		tThreadInfo.pcTask = this;
		tThreadInfo.dwIndex = dwIndex;
		Print("[start] pthread_create() dwIndex: %d\r\n", tThreadInfo.dwIndex);
		pthread_create(&thread, NULL, thread_func,(void*)&tThreadInfo);
		Print("[end] pthread_create() dwIndex: %d\r\n", tThreadInfo.dwIndex);
		usleep(10000);
	}
	Print("create end\r\n");
}

原因是 create_thread() 中,线程函数参数是定义在for循环体中的临时变量。
这会导致一些负面影响:

首先,在 pthread_create 中,最好不要将 线程句柄 和 线程函数参数 定义成临时变量,
因为可能临时变量都销毁了,线程函数才姗姗来迟的被调用起来,此时的参数指针已经成了野指针了!!!

其次,在 for 循环体内定义临时变量,那么此变量可以认为在每次循环中都是一个独立的临时变量,但可能每次循环中的临时变量进栈出栈的变量地址都是一样的!这会导致 这次循环中的临时变量会被下次循环破坏,每次循环中的临时变量不再是独立的啦。还有可能C编译器对for循环中定义的临时变量有优化,优化成只用一个临时变量负责所有循环,这也会导致各次循环不在是独立的啦。

基于上面的分析,下面我们对 create_thread() 进行修改优化:

// 此次测试使用全局变量
pthread_t thread;
TThreadInfo tThreadInfo[TaskNum] = { 0 }; //定义大小为 5 的结构体数组

// 创建 5 个线程
void create_threadEx()
{
	for(u32 dwIndex = 0; dwIndex < TaskNum; dwIndex++)
	{
		tThreadInfo[dwIndex].pcTask = this;
		tThreadInfo[dwIndex].dwIndex = dwIndex;
		Print("[start] pthread_create() dwIndex: %d\r\n", tThreadInfo[dwIndex].dwIndex);
		pthread_create(&thread, NULL, thread_func, (void*)&tThreadInfo[dwIndex]);
		Print("[end] pthread_create() dwIndex: %d\r\n", tThreadInfo[dwIndex].dwIndex);
		usleep(10000);
	}
	Print("create end\r\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值