C++用pthread_create()创建线程
pthread_create()是Linux中创建线程的一种方式。
#include<pthread.h> int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,(void*)(*start_rtn)(void*) ,void *arg); //第一个参数为指向线程标识符的指针。 //第二个参数用来设置线程属性。 //第三个参数是线程运行函数的起始地址。 //第四个参数是运行函数的参数。 //pthread_create() 在调用成功完成之后返回零。其他任何返回值都表示出现了错误。
用到多线程,就用for语句循环创建多个线程,但是出现了一些问题,特此记录下。
原代码:
pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t)); for(int a=0;a<num_threads;a++) pthread_create(&pt[a],NULL,function,&a); for(int a=0;a<num_threads;a++) pthread_join(pt[a],NULL);
创建线程时是需要把a传入函数function中的,但是,这样会出现混乱,比如,我们需要往第0个线程传入参数0,实际上运行结果显示传入第0个线程的参数不是0。
网上查询资料之后,大概问题就是,CPU运行速度很快,而pthread_create()创建线程要有一定的时间,在pthread_create()创建线程再去按照之前参数a的地址去取a时,循环中a的值已经发生了变化,这就造成传入函数function的参数值不对。
既然这样,就让主线程循环时等一下pthread_create(),于是代码变成下面这样:
pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t));
for(int a=0;a<num_threads;a++)
{
pthread_create(&pt[a],NULL,function,&a);
sleep(1); //#include<unistd.h>
}
for(int a=0;a<num_threads;a++) {
pthread_join(pt[a],NULL);
}
循环时主线程挂起1秒钟,pthread_create()就创建线程完毕了,但这样带来的问题就是:我们使用多线程的初衷就是并行运算、提升效率,但每创建一个线程就能停1秒,如果我们创建线程的次数比较多,那将大大影响程序的整体运行效率。试了一下,如果将sleep(1)改成usleep(1000),即睡眠1000微秒(1毫秒),仍可能出现错误。
通过网上资料,经过实践,发现以下两种方法可以解决:
1、实现开辟一块空间存储创建多线程时所需要传入的参数,这样每个线程的参数的地址就不会乱套。
2、在循环创建线程时,我们不直接把循环的控制变量(如上例中的a)直接传入多线程的函数中,我们另外申请一块空间,存储在这块空间上,到时再从这块空间取值就行了。
种方法的解决方法如下:
//第一种方法 pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t)); int order[num_threads]; for(int a=0;a<num_threads;a++) order[a]=a; for(int a=0;a<num_threads;a++) pthread_create(&pt[a],NULL,function,&order[a]); for(int a=0;a<num_threads;a++) pthread_join(pt[a],NULL); //第二种方法 pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t)); for(int a=0;a<num_threads;a++) { int* temp=(int*)malloc(sizeof(int)); *temp=a; pthread_create(&pt[a],NULL,function,(void*)temp); } for(int a=0;a<num_threads;a++) pthread_join(pt[a],NULL);
两种效果方法差不多,但是第二种方法使用malloc申请了动态内存,而且还没有释放,所以不是太好。