Linux:线程概念及基本操作

Linux学习目录


1、 线程的概念

  • 1、线程是进程内部的一个执行分支,线程量级很小。(所谓的内部就是在进程的地址空间内运行)
  • 2、一切进程至少都有一个线程

这里写图片描述

PCB1相当于主线程,新线程PCB2、PCB3、PCB4相当于用vfork创建出来的,它们指向同一块地址空间,它们隶属于同一个进程,但是他们有着自己的线程ID

1.1、线程和进程的区别

  • 1、进程是资源竞争的基本单位
  • 2、linux下没有真正意义的线程,因为linux下没有给线程设计专有的结构体,它的线程是用进程模拟的,而它是由多个进程共享一块地址空间而模拟得到的。
  • 3、创建一个线程的资源成本小,工作效率高
  • 4、Linux下cpu所看到的所以进程都可以看成轻量级的进程
  • 5、进程是承担分配系统资源的基本实体,进程具有独立性(但进程间通信打破了独立性)
  • 6、线程是cpu或操作系统调度的基本单位,线程具有共享性

1.2、线程共享的资源

  • 同一块地址空间
  • 文件描述符表()
  • 每种信号的处理方式(如:SIG_DFL,SIG_IGN或者自定义的信号优先级)
  • 当前工作目录
  • 用户id和组id

1.3、线程独立的资源

  • 线程会产生临时变量,临时变量保存再栈上,所以每个线程都有自己的私有栈结构
  • 每个线程都有私有的上下文信息。
  • 线程ID
  • 一组寄存器的值
  • errno变量
  • 信号屏蔽字以及调度优先级

1.4、线程控制

1.4.1、线程创建

1:POSIX线程库
  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
  • 要使用这些函数库,要通过引入头文件
#include<pthread.h>
  • 链接这些线程函数库时要使用编译器命令的“-lpthread”选项
2:函数格式
1、创建线程
功能:创建一个新的线程
原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*star
t_routine)(void*), void *arg);
参数
thread:返回线程ID
attr:设置线程的属性,attr为NULL表⽰示使⽤用默认属性
start_routine:是个函数地址,线程启动后要执⾏的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
2、获取线程id
函数1:syscall(int number,...)//获取内核线程id
函数2:pthread_self()//获取用户态线程id

了解内核线性和用户态线程可参考这里:
https://blog.csdn.net/zhangye3017/article/details/80396745

3、终止线程
  • return返回
  • pthread_exit(void *val)
功能:线程终止 原型
void pthread_exit(void *value_ptr);
参数
value_ptr:value_ptr 
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)
  • pthread_canel()取消线程,返回-1
功能:杀死一个执行中的线程
原型
int pthread_cancel(pthread_t thread);
参数
thread:线程ID
返回值:成功返回0;失败返回错误码

一个线程可以自己把自己杀死,也可以被别人杀死

eg1:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>

void *thread_run(void* arg)
{

    while(1)
    {
        printf("new thread,thread is :%u,pid:%d\n",pthread_self(),getpid());
    sleep(1);
    pthread_exit(NULL);
    }
}

int main()
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread_run,NULL);
    while(1)
    {//pthread_self()是获取线程id
        printf("main thread,thread is :%u,pid:%d\n",pthread_self(),getpid())    ;
        sleep(3);
        pthread_cancel(pthread_self());//杀死自己
    }

    return 0;
}

主线程和新线程那个先运行完全由调度器决定,这里主线程先打印一句后,时间片轮转到新线程,新线程打印后遇pthread_exit(NULL)退出,主线程再睡3秒,遇到 pthread_cancel(pthread_self())退出。

这里写图片描述

使用pthread_cancel()函数需要注意:
pthread_cancel()函数并不是立即退出的,直到遇到cancel点它才会退出,而系统调用都是cancel点(如printf函数)。
如果没有cancel点就需要人为手动加cancel点

手动添加cancel点函数
pthread_testcancel(void)
4、线程等待

为什么要线程等待呢?

  • 1、就像子进程死亡,需要父进程等待并回收一样,新线程死亡,其空间没有被释放,需要主线程等待回收
  • 2、如果再创建新的线程不会复用刚才退出线程的地址空间
int pthread_join(pthread_t thread,void **retval)
thread:线程ID
value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0;失败返回错误码

作用:
- 主线程等待新线程退出,否则就会导致进程的内存泄漏
- 回收新线程的退出结果

eg2:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>

void *thread_run(void* arg)
{

    printf("new thread,thread is :%u,pid:%d\n",pthread_self(),getpid());
    sleep(3);
    return (void*)1;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread_run,NULL);
    sleep(3);
    void* ret;//获取新线程返回的信息
    pthread_join(tid,&ret);
    printf("join new thread success,ret :%d\n",(int)ret);//打印退出码
    return 0;
}

这里写图片描述

5、查看线程

这里写图片描述

1.5、分离线程

为什么要分离线程?

  • 如果新线程创建后,不用pthread_join()等待回收新线程,那么就会造成内存泄漏,但是当等待新线程时,主线程就会一直阻塞,影响主线程处理其他链接要求,这时候就需要一种办法让新线程退出后,自己释放所有资源,因此产生了线程分离

1:线程自己退出后释放自己资源


int pthread_detach(pthread_self())

2:线程组内其他线程对目标线程进行分离

int pthread_detach(pthread_t thread)

返回值:成功返回0,失败返回错误码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread_run( void * arg  )
{
    printf("new thread dead\n");
    pthread_detach(pthread_self());
    return NULL;
}
int main( void  )
{
    pthread_t tid;
    if ( pthread_create(&tid, NULL, thread_run, "thread1 run...") != 0  ) {
        printf("create thread");
    }
    void *ret;
    sleep(1);
    if ( pthread_join(tid, NULL ) == 0  ) 
    {
        printf("pthread wait success,ret:%d\n",(int )ret);

    } 
    else 
    {
        printf("pthread wait failed\n");

    }
    return 0;
}

这里写图片描述
可以看出,如果一个线程进行了分离,那么就不需要pthread_join操作了。

  • 14
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值