Linux线程基础--笔记

1、线程概念

        进程实际上并不执行什么,只是维护应用程序所需的各种资源,而线程则是真正的执行实体。

        所以线程是轻量级的进程(LWP: light weight process),在Linux环境下线程的本质仍是进程。

        为了让进程完成一定的工作,进程必须至少包含一个线程

        操作系统以进程为单位分配系统资源所以进程是CPU分配资源的最小单位线程是进程的一个实体,是CPU调度和分派的基本单位。线程自己基本商不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他线程共享进程所拥有的全部资源。

2、线程的特点

        类Unix早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程的概念

因此在这类系统中,进程和线程关系密切:

  1. 线程是轻量级进程,也有PCB,创建线程使用的底层函数和进程一样,都是clone
  2. 从内核里看进程和线程是一样的,都有各自不同的PCB
  3. 进程可以蜕变成线程
  4. 在linux下,线程是最小的执行单位;进程是最小的分配资源单位

实际上,无论是创建进程的fork,还是创建线程的pthread_create,底层实现都是调用同一个内核函数clone:

如果复制对方的地址空间,那么产生出一个“进程”;

如果共享对方的地址空间,就产生一个“线程”。      

        Linux内核时不区分进程和线程的,只在用户层面上进行区分。所以,线程所有操作函数pthread_*是库函数,而非系统调用。

3、线程共享资源

  1. 文件描述表
  2. 每种信号的处理方式
  3. 当前工作目录
  4. 用户ID和组ID

内存地址空间(.text/.data/.bss/heap/共享库)

4、线程非共享资源

  1. 线程id
  2. 处理器线程和栈指针(内核栈)
  3. 独立的栈空间(用户空间栈)
  4. errno变量
  5. 信号屏蔽字
  6. 调度优先级

5、线程优缺点

优点:

  1. 提高程序并发性
  2. 开销小
  3. 数据通信、共享数据方便

缺点:

  1. 库函数,不稳定
  2. 调试、编写困难、gdb不支持
  3. 对信号支持不好

优点相对突出,缺点均不是硬伤。Linux下由于实现方式导致进程、线程差别不是很大。

6、常用操作

6.1 线程号

        进程号在整个系统中是唯一的,但线程号不同,它只在它所属的进程环境中有效。

        进程号用pid_t数据类型表示,是一个非负整数。线程号则用pthread_t数据类型来表示,Linux使用无符号长整数表示。

        有的系统在实现pthread_t的时候,用一个结构体来表示,所以在可移植的操作系统实现不能把它为整数处理

6.2 获取线程号
#include<pthread.h>
pthread_t pthread_self(void);
功能:
    获取线程号
参数:
    无
返回值:
    调用线程的线程ID。
6.3 判断线程号是否相等
int pthread_equal(pthread_t t1, pthread_t t2);
功能:
    判断线程t1和t2是否相等。为了方便移植,尽量使用函数来比较线程id
参数:
    t1, t2: 待判断的线程号
返回值:
    相等:非0
    不相等:0
6.4 线程的创建
int pthread_create(pthread_t *thread,
                  const pthread_t *attr,
                  void *(*start_routine)(void *),
                  void *arg);
功能:
    创建一个线程
参数:
    thread: 线程标识符地址
    attr: 线程属性结构体地址,通常设置为NULL
    start_routine: 线程函数的入口地址
    arg: 传给线程函数的参数
返回值:
    成功:0
    失败:非0
6.5 线程回收
int pthread_join(pthread_t thread, void **retval);
功能:
    等待线程结束(此函数会阻塞),并回收线程资源,类似于进程的wait()函数。如果线程已经结束,那么该函数会立即返回。
参数:
    thread: 被等待的线程号
    retval: 用来存储线程退出状态的指针的地址
返回值:
    成功:0
    失败:非0

pthread_join得到的终止状态是不同的,总结如下:

  1. 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
  2. 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED.
  3. 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
6.6 线程分离

        一般情况下,线程终止后,其终止状态一直保留到其他线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。

        不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

#include<pthread.h>
int pthread_detach(pthread_t thread);
功能:
    使调用线程与当前进程分离,分离后不代表此线程不依赖于当前进程,线程分离的目的是将线程资源的回收工作交由系统自动来完成,也就是说当被分离的线程结束之后,系统会自动回收它的资源。所以,此函数不会阻塞
参数:
    thread: 线程号
返回值:
    成功:0
    失败:非0
6.7 线程取消
#include<pthread.h>
int pthread_cancel(pthread_t thread);
功能:
    杀死(取消)线程
参数:
    thread: 目标线程ID
返回值:
    成功:0
    失败:出错编号

注意:线程的取消并不是实时的,而又一定的延时。需要等待线程到达某个取消点(检查点)。

杀死线程也不是立刻就能完成,必须要到达取消点。

取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用creat,open,pause,close,read,write......

可粗略认为一个系统调用(进入内核)即为一个取消点。

  • 40
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值