线程创建、终止、回收

学习了线程概念 之后,我们就可以学习一些函数了。

1.pthread_create 创建线程

pthread_t *thread:传递一个pthread_t变量地址进来,用于保存新线程的tid(线程ID)

const pthread_attr_t *attr:线程属性设置,如使用默认属性,则传NULL

void *(*start_routine) (void *):函数指针,指向新线程应该加载执行的函数模块

返回值:成功返回0失败返回errno,当函数调用失败多线程的时候,再去设置errno全局变量容易搞混,所以线程采用函数失败,直接返回错误码

2.pthread_self-获取调用线程tid

#include <pthread.h>


pthread_t pthread_self(void);

小实验

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
//-lpthread 线程库的函数 链接
void *th_fun(void*arg){
    int *p=(int *)arg;

    printf("thread PID=%d\n",getpid()); //线程里面的进程号
    printf("thread ID=%x\n",(unsigned int)pthread_self()); //线程里面的线程号
    printf("thread *arg =%d\n",*p);

    
   // while(1);
}

int main(){
    pthread_t tid;
    int n=10;

    pthread_create(&tid,NULL,th_fun,(void*)&n);
//1创建线程
//2线程号填写到tid
//3返回函数调用
    sleep(1);
    printf("main thread ID=%x\n",(unsigned int)pthread_self());//主控线程号
    printf("main child thread ID=%x\n",(unsigned int)tid);//主控线程的线程号
    printf("main PID=%d\n",getpid());//主控线程的进程号
    
  //  while(1);
    return 0;
}

 Compile and link with -lpthread.

使用函数记得链接到pthread库

把sleep改成在两个线程都while(1),另开一个终端

ps -Lw 17379可查看相应信息

小小的实例中其实需要注意的点有很多

(1)如果main函数中没有 sleep,会出现下面情况

想一想为什么?

因为此时两个线程同时进行,而此时CPU直接先把主控线程return 0执行完,之后整个进程结束,之中的线程也就无意义 。
 

(2)得到子线程ID号的2种方法

一个是子线程里自己调pthread_self

一个是通过主线程pthread_create 参数&tid 得到

而两者是否等价?

两者并不等价,因为在主线程得到tid需要一定时间

需要1、创建线程,2、线程号填写到tid,3、返回函数调用,可能这时子线程已经执行完结束了,此时的tid也就无意义。而子进程中调pthread_self,会得到当时的线程号。

3.pthread_exit  线程退出

如果任意一个线程调用了exit或_exit(*),则整个进程的所有线程都终止,由于从main函
数return也相当于调用exit,为了防止新创建的线程还没有得到执行就终止,我们在main函
数return之前延时1秒,这只是一种权宜之计,即使主线程等待1秒,内核也不一定会调度新
创建的线程执行

(*)_exit是比exit更底层的一个函数,exit负责关闭C标准的文件流stdin、stdout等,刷新缓冲区

_exit是由linux提供的,直接导致进程退出,关闭未关闭的文件描述符

即exit会接着向下调用_exit

为了避免刚刚的尴尬,我们需要学习线程退出

该函数仅退出本线程

void *retval:线程退出时传递出的参数,可以是退出值或地址,如是地址时,不能是线程内部申请的局部地址。

 子线程返回一个地址,如果返回自己栈上的地址就没有意义(这里不理解的可以看博主上一篇线程概念)可以返回全局变量或者堆。

4.pthread_join  线程回收

类似于进程里的wait。

它用来回收线程的退出值,如果线程没有退出,该函数阻塞等待。

并且回收完线程以后会把线程资源释放掉。(PCB)

(防止其成为“僵尸线程”)

pthread_t thread:指定回收线程的tid
void **retval:接收退出线程传递出的返回值

        注意:这是一个二重指针,因为退出线程返回值是一个void*,这里我们要保存一重指针
返回值:成功返回0,失败返回错误号

thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,

总结如下:
如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返
回值。
如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存
放的是常数PTHREAD_CANCELED。
如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给
pthread_exit的参数。
如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

5.pthread_cancel

一个进程内某个线程可以取消另一个线程.

 被取消的线程,退出值,定义在Linux的pthread库中常数PTHREAD_CANCELED的值是-1。

总实例:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
void* thr_fn1(void *arg){
    printf("thread 1 returning\n");
    return (void*)1;
}
void* thr_fn2(void *arg){
    printf("thread 2 exiting\n");
    pthread_exit((void*)2);//线程结束
}
void* thr_fn3(void *arg){
    while(1){
        printf("thread 3 writing\n");
        sleep(1);
    }
}

int  main(void){
    pthread_t tid;
    void *tret;
    pthread_create(&tid,NULL,thr_fn1,NULL);
    pthread_join(tid,&tret);//回收线程,线程退出值保存在tret(二重指针)
    //前面没结束后面不能执行
    printf("thread 1 exit code %ld\n",(long)tret);


    pthread_create(&tid,NULL,thr_fn2,NULL);
    pthread_join(tid,&tret);
    printf("thread 2 exit code %ld\n",(long)tret);

    pthread_create(&tid,NULL,thr_fn3,NULL);
    sleep(3);
    pthread_cancel(tid);//主控线程去取消线程3
    //这里退出的宏应该PTHREAD_CANCELED
    
    pthread_join(tid,&tret);
    printf("thread 3 exit code %ld\n",(long)tret);

    return 0;
}


最后,感兴趣的同学可以来一起讨论。

关注不亏,欢迎关注、点赞、评论。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值