红联Linux门户
Linux帮助

Linux多线程编程——线程调用函数时传入参数

发布时间:2017-01-16 09:23:01来源:blog.csdn.net/angon823作者:is_angon
当调用pthread_create  第三个和第四个参数不为空时,要注意第四个参数的传递方法。
 
一段流行的代码:
#include <iostream>  
#include <pthread.h>   
using namespace std;   
#define NUM_THREADS 10  
void* say_hello(void* args)  
{  
int i = *((int*)args);//对传入的参数进行强制类型转换,由无类型指针变为整形数指针,然后再读取;  
cout << "hello in " << i << endl;  
}  
int main()  
{  
pthread_t tids[NUM_THREADS];  
cout << "hello in main..." << endl;  
for(int i = 0; i < NUM_THREADS; ++i)  
{  
int ret = pthread_create(&tids[i], NULL, say_hello, (void *)&i);//传入的时候必须强制转换为void* 类型,即无类型指针  
cout << "Current pthread id =" << tids[i] << endl;//这里学会使用tids数组打印创建的进程id信息;
if (ret != 0)  
{  
cout << "pthread_create error: error_code=" << ret << endl;  
}  
pthread_exit(NULL);  
}
 
程序运行结果:
hello in main...
Current pthread id =140210171029248
Current pthread id =140210162636544
Current pthread id =140210154243840
Current pthread id =140210145851136
Current pthread id =140210137458432
Current pthread id =140210129065728
Current pthread id =140210120673024
Current pthread id =140210112280320
hello in 6
hello in 6
hello in 6
hello in 6
hello in hello in 6
hello in 6
7
Current pthread id =140210103887616
Current pthread id =140210095494912
hello in 10
hello in 10
hello in 10
 
显然与预期不一致,我猜想原因:我们 pthread_create的时候,传入i的方式是 取i的地址指针 再强制转换为 无类型指针,然后在sayhello函数里,再把无类型指针转换为int类型指针(这样做是为了满足phtread_create的参数设定),再通过 * 号取值。这意味着,我们是通过指向 i 的指针来获取i的值的,但是在多个线程切换间,i 的值已经改变了,但是指向 i 的地址并没有改变,多个线程随机竞争执行,所以通过 i 的地址 取值,显然取到的结果和预期的很难一致。
 
流行的一种做法:把 i 赋值给一个数组保存,这样就避免了在同一地址取值。
#include <iostream>  
#include <pthread.h>  
using namespace std;  
#define NUM_THREADS 10  
void* say_hello(void* args)  
{  
cout << "hello in thread " << *((int *)args) << endl;  
}  
int main()  
{  
pthread_t tids[NUM_THREADS];  
int indexes[NUM_THREADS];//用个数组来保存i的值,就不会变了  
for(int i = 0; i < NUM_THREADS; ++i)  
{  
indexes[i] = i;//先保存i的值,在调用线程就不会出现问题了  
int ret = pthread_create( &tids[i], NULL, say_hello, (void *)&(indexes[i]) );  
if (ret != 0)  
{  
cout << "pthread_create error: error_code=" << ret << endl;  
}  
}  
for (int i = 0; i < NUM_THREADS; ++i)  
pthread_join(tids[i], NULL);  
}
 
运行结果:
hello in main..
Current pthread id = 140457201362688
Current pthread id = 140457192969984
Current pthread id = 140457184577280
Current pthread id = 140457176184576
Current pthread id = 140457167791872
Current pthread id = 140457159399168
Current pthread id = 140457151006464
Current pthread id = 140457142613760
Current pthread id = 140457134221056
Current pthread id = 140457125828352
hello in 3
hello in 4
hello in 5
hello in 6
hello in 7
hello in 8
hello in 9
hello in 2
hello in 1
hello in 0
 
还有一种写法也可以: 直接把 i 的值 强制转换成 无类型指针 传过去,然后再 在 被调函数里 把无类型指针参数 强制转换回来,注意,在64 位Linux机里,指针是8个字节,int是4个字节,long也是8个字节,所以必须转换成long型,否则会因丢失精度而报错。从这里也可以看出来,第一个程序结果和预期不一致 不是因为 i 的值和预期不一致,而是 i 的地址出问题了。
#include <iostream>
#include <pthread.h>  
using namespace std;
#define NUM_THREADS 10 //线程数
void* say_hello( void* args )
{
cout << "hello in " << long(args) <<  endl;
int main()
{
pthread_t tids[NUM_THREADS]; //线程id
cout << "hello in main.." << endl;
for( int i = 0; i < NUM_THREADS; ++i )
{
int ret = pthread_create( &tids[i], NULL, say_hello, (void*)i );   
//直接把i的值传过去
cout << "Current pthread id = " << tids[i] << endl;   
//用tids数组打印创建的进程id信息
if( ret != 0 ) //创建线程成功返回0
{
cout << "pthread_create error:error_code=" << ret << endl;
}
}   
for( int i = 0; i < NUM_THREADS; ++i )
{  
pthread_join(tids[i],NULL);  
}
}
 
运行结果:
hello in main..
Current pthread id = 140406320125696
Current pthread id = 140406311732992
Current pthread id = 140406303340288
Current pthread id = 140406294947584
Current pthread id = 140406286554880
Current pthread id = 140406278162176
Current pthread id = 140406269769472
Current pthread id = 140406261376768
Current pthread id = 140406252984064
Current pthread id = 140406244591360
hello in 6
hello in 7
hello in 8
hello in 9
hello in 5
hello in 4
hello in 3
hello in 2
hello in 1
hello in 0
 
本文永久更新地址:http://www.linuxdiyf.com/linux/27843.html