hello.c
关键词:pthread_exit()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
sleep(2);
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0;t<NUM_THREADS;t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
printf("return\n");
return 0;
}
这里主线程创建了5个子线程,子线程中会在休眠2S后打印传入的线程id;代码的输出打印如下。
In main: creating thread 0
In main: creating thread 1
In main: creating thread 2
In main: creating thread 3
In main: creating thread 4
Hello World! It's me, thread #1!
Hello World! It's me, thread #0!
Hello World! It's me, thread #2!
Hello World! It's me, thread #3!
Hello World! It's me, thread #4!
如果我们将main()中的pthread_exit()屏蔽,运行后的输出如下。
In main: creating thread 0
In main: creating thread 1
In main: creating thread 2
In main: creating thread 3
In main: creating thread 4
说明了如下信息:
- 主线程创建子线程后,需要使用一些机制确保子线程执行完毕后进程再结束退出;pthread_exit()是其中的一种方法。
- 主线程调用pthread_exit()后,主线程会直接退出(因为之后的printf()调用并没有打印出来信息);但进程会在各个子线程执行完毕后再退出。
- 主线程直接return后会导致整个进程直接退出,使得子线程尚未执行printf()就被销毁。
hello_args
关键词:参数传递
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = *(long*)threadid;
sleep(2);
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0;t<NUM_THREADS;t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
printf("return\n");
return 0;
}
这是一个错误的线程参数传递调用示例,相比上面的hello.c这段代码只是将之前的值传递((void*)t)改为了指针传递((void*)&t),同时子线程接受参数时也做了相应的修改,但它是错误的,为何?
回答:hello.c中使用值传递的形式,t当时的值会产生拷贝副本保存在子线程对应的堆栈内,t之后的变化不会影响子线程的使用;而hello_args.c中传给子线程的是t的指针,t之后的变化会影响到访问它的子线程。
如何在仍然使用指针传递的方法下解决该问题?避免各个线程访问共同的内存即可;譬如将t声明为数组,每个子线程访问独立的数组元素。使用指针传递参数更加自由,但需要注意由此可能带来的调用bug。