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

  • Post author:
  • Post category:其他


公司某个程序需要在启动时创建多个线程,我们使用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");
}



版权声明:本文为lijian2017原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。