Linux ----线程的创建、等待退出

一、线程的创建和退出

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>
    23 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:清理函数是弹栈压栈的效果。

发布了1 篇原创文章 · 获赞 0 · 访问量 6

猜你喜欢

转载自blog.csdn.net/weixin_43574252/article/details/104900563