一、线程的创建和退出
1、创建一个简单的线程
#include <func.h>
void* threadFnc(void *p){
printf("I am child thread\n");
}
int main(int argc,char* argv[])
{
pthread_t pth;//创建一个线程ID
int ret=pthread_create(&pth,NULL,threadFnc,NULL);//创建线程
THREARD_ERRORCHECK(ret,"pthread_create");
usleep(1);
printf("I am main .\n");
return 0;
}
结果:
代码分析:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
- 第一个参数指的是线程ID,
- 第二个参数为NULL,表示普通线程,
- 第三个参数表示子线程函数,
- 第四个参数是向子线程函数传参。
2、传参建线程
#include <func.h>
void* threadFnc(void *p){
printf("I am child thread\n");
printf("%s\n",(char *)p);
}
int main(int argc,char* argv[])
{
pthread_t pth;
char *pArr=(char *)malloc(20);
strcpy(pArr,"helloworld");
int ret=pthread_create(&pth,NULL,threadFnc,pArr);
THREARD_ERRORCHECK(ret,"pthread_create");
pthread_join(pth,NULL);
printf("I am main .\n");
return 0;
}
3.传整型参数
#include <func.h>
void* threadFnc(void *p){
printf("I am child thread\n");
printf("%d\n",*(int *)p);
}
int main(int argc,char* argv[])
{
pthread_t pth;
//char *pArr=(char *)malloc(20);
//strcpy(pArr,"helloworld");
int val=10;
int ret=pthread_create(&pth,NULL,threadFnc,&val);
THREARD_ERRORCHECK(ret,"pthread_create");
pthread_join(pth,NULL);
printf("I am main .\n");
return 0;
}
结果:
代码分析:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
最后一个参数传递整型数地址。在线程处理函数中要通过强转的方式来取值。
4.两个线程
注意,这里采用的形参,利用(void *)强转类型val(64位系统中指针类型是八位,long型也是八位)
#include <func.h>
void* threadFnc(void *p){
printf("I am child thread\n");
printf("%ld\n",(long)p);
}
int main(int argc,char* argv[])
{
pthread_t pth,pth1;
long val=1;
int ret=pthread_create(&pth,NULL,threadFnc,(void *)val);
THREARD_ERRORCHECK(ret,"pthread_create");
val=2;
ret=pthread_create(&pth1,NULL,threadFnc,(void *)val);
THREARD_ERRORCHECK(ret,"pthread_create");
pthread_join(pth,NULL);
pthread_join(pth1,NULL);
printf("I am main .\n");
return 0;
}
结果:
代码分析:若按照3的方式写函数,将发现结果是输出两个2。
采用这种方式的优势在于,void*与long类型在64位系统中都是八位存储。打印接收时同样要强转成long类型,否则会发生访问越界的现象。
5、主线程和子线程分别对一个数加10000000
#include <func.h>
2 #define N 10000000
3 void* threadFnc(void *p){
4 int i=0;
5 for(i=0;i<N;i++){
6 *(int *)p+=1;
7 }
8 printf("%d\n",*(int *)p);
✹ 9 }
✹ 10 int main(int argc,char* argv[])
11 {
12 pthread_t pth;
13 //char *pArr=(char *)malloc(20);
14 //strcpy(pArr,"helloworld");
15 int val=10;
16 int ret=pthread_create(&pth,NULL,threadFnc,&val);
17 THREARD_ERRORCHECK(ret,"pthread_create");
18 int i;
19 for(i=0;i<N;i++){
20 val+=1;
21 }
22 pthread_join(pth,NULL);
23 printf("I am main .\n");
24 return 0;
25 }
结果:
分析:此结果是正确的。不能加到2000000的原因是由于并发现象。可以通过加解锁来避免并发的产生。
6.线程的退出
1 #include <func.h>
2 void print(){
3 printf("I am print.\n");
4 pthread_exit(NULL); //退出线程
5 }
? 6 void* threadFnc(void *p){
7 printf("I am child thread\n");
8 print();
9 printf("I am after print.\n");
10 return NULL;
11 }
? 12 int main(int argc,char* argv[])
13 {
14 pthread_t pth;
15 int ret=pthread_create(&pth,NULL,threadFnc,NULL);
16 THREARD_ERRORCHECK(ret,"pthread_create");
17 pthread_join(pth,NULL);
18 printf("I am main .\n");
19 return 0;
20 }
结果:
代码分析:
void pthread_exit(void *retval);
用于正常返回,直接退出线程。
二、线程等待退出
1.主线程拿子线程的返回值(子线程自己申请空间)
1 #include <func.h>
2
3 void* threadFnc(void *p){
4 p=malloc(20);
5 strcpy((char *)p,"I AM GOOG!");
6 printf("I am child thread.%s\n",(char *)p);
7 pthread_exit(p);
8 }
? 9 int main(int argc,char* argv[])
10 {
11 pthread_t pth;
12 int ret=pthread_create(&pth,NULL,threadFnc,NULL);
13 THREARD_ERRORCHECK(ret,"pthread_create");
14 char *res;
15 ret=pthread_join(pth,(void **)&res);
16 THREARD_ERRORCHECK(ret,"pthread_join");
17
18 printf("I am main .%s\n",res);
19 return 0;
20 }
结果:
代码分析:
void pthread_exit(void *retval);
参数可以填返回值,注意,这里是void *类型。
主线程中通过pthread_join接收返回值。
int pthread_join(pthread_t thread, void **retval);
- 第一个参数表示子进程ID
- 第二个参数表示接收的返回值存储在哪里
接收成功返回值0。
2.子线程返回int型数
pthread_join.c ?? buffers
1 #include <func.h>
2
3 void* threadFnc(void *p){
4 printf("I am child thread.val=%ld\n",(long)p);
5 pthread_exit((void *)2);
6
7 }
8 int main(int argc,char* argv[])
9 {
10 pthread_t pth;
11 long val=1;
12 int ret=pthread_create(&pth,NULL,threadFnc,(void *)val);
13 THREARD_ERRORCHECK(ret,"pthread_create");
14 long res;//不能用int,否则会访问越界
15 pthread_join(pth,(void **)&res);
16 printf("I am main.and getval=%ld\n",res);
17 return 0;
18 }
结果:
3.线程的取消
1 #include <func.h>
2
✹ 3 void* threadFnc(void *p){
4 printf("I am child thread\n");
5 return NULL;
6 }
✹ 7 int main(int argc,char* argv[])
8 {
9 pthread_t pth;
10 int ret=pthread_create(&pth,NULL,threadFnc,NULL);
11 THREARD_ERRORCHECK(ret,"pthread_create");
12 ret=pthread_cancel(pth);
13 THREARD_ERRORCHECK(ret,"pthread_cancel");
14 long res;
15 ret=pthread_join(pth,(void **)&res);
16 THREARD_ERRORCHECK(ret,"pthread_join");
17 printf("child return :%ld\n",res);
18 printf("I am main .\n");
19 return 0;
20 }
结果:
cancel成功,子线程返回值为-1.
当子进程处于while(1)时不可被cancel
4、资源清理
子进程申请资源并清理
代码:
#include <func.h>
2 void cleanup(void *p)
3 {
4 free(p);
5 printf("free end.\n");
6 }
7 void* threadFnc(void *p){
8 p=malloc(20);
9 strcpy((char *)p,"clean up");
10 pthread_cleanup_push(cleanup,p);
11 pthread_cleanup_pop(1);
12 return NULL;
13 }
✹ 14 int main(int argc,char* argv[])
15 {
16 pthread_t pth;
17 int ret=pthread_create(&pth,NULL,threadFnc,NULL);
18 THREARD_ERRORCHECK(ret,"pthread_create");
19 ret=pthread_cancel(pth);
20 THREARD_ERRORCHECK(ret,"pthread_cancel");
21 long res;
22 ret=pthread_join(pth,(void **)&res);
23 THREARD_ERRORCHECK(ret,"pthread_join");
24 printf("child return :%ld\n",res);
25 printf("I am main .\n");
26 return 0;
27 }
结果:
tips:清理函数是弹栈压栈的效果。