线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41027326/article/details/79972780
1. 线程的概念

    (1)线程是进程内部的一个执行流, 一个进程至少有一个线程.
    (2)线程是调度的基本单位, 同时线程的切换粒度是比进程执行粒度更小
    (3)线程和线程的大部分数据共享
    (4)在 Linux 下没有真正的线程, 它是用进程模拟实现线程

2.进程和线程

    (1) 进程是资源分配的基本单元, 线程是调度的基本单位
    (2)线程的创建销毁都比进程的创建以及销毁花费的代价要小, 因为创建进程需要给进程分配数据结构, 同时需要给进程分配一系列的资源, 销毁一个进程时需要回收该进程的一系列资源, 而创建线程的时候, 只需要给线程创建一个 PCB, 释放的时候将线程的 PCB 释放即可
    (3)线程的调度比进程的调度花费的粒度小.。知识因为进程在切换时必须要保存进程先关的上下文数据, 页表等相关信息,而进程在切换时,至少它的页表不用替换
    线程共享进程数据,但线程也拥有自己的一部分数据, 如线程 ID, 一组寄存器(上下文数据) , 栈, error, 信号屏蔽字, 调度优先级.
    (4)同一地址空间中, 其数据段和代码段都是共享的, 如果定义一个函数, 各个线程都可以调用, 如果定义一个全局变量, 各个线程也都可以访问
    (5)各个线程都共享进程的文件描述符, 信号处理方式, 当前工作目录, 用户 ID以及组 ID

3.线程相比进程的优点

    (1)创建一个新线程的代价比创建一个新进程的代价小的多, 因为系统在创建进程的时候需要给进程创建 PCB, 同时还需要给进程创建一系列的资源, 而在创建线程的时候只需要给其创建 PCB即可.
    (2)线程占用的资源比进程占用的资源少很多, 在单处理机上, 线程能够达到并行, 而进程只能实现并发
    (3)在一个等待慢速I/O的进程中, 为了提高程序运行效率, 此时就可以创建许多线程, 其中一部分线程执行非 I/O 任务, 而另一部分线程执行 I/O 等待, 这样就大大提高了程序的执行效率
    (4)在计算密集型应用中为了提高运行效率,可以将不同任务分派给不同的线程, I/O密集型应用可以将不同的 I/O 任务分派给不同的线程

4.线程的缺点

    (1)性能方面, 在处理计算密集型任务时,如果计算密集型线程的数量 远远大于处理机的数量时, 此时为了保证线程之间的同步,调度等可能会降低系统的性能
    (2)健壮性方面:线程是共享进程资源时,此时如果线程和线程之间共享了不该共享的数据时, 此时可能会导致系统产生一些数据不一致性问题, 从而导致无法想象的后果
    (3)缺乏访问控制:在一个进程中, 如果某一个线程出错, 将会导致整个进程出错.
    (4)编写困难: 编写多线程程序比但线程程序困难

5. 线程控制

    (1)线程的创建
这里写图片描述
    其中pthread_t 是一种用户提供的类型, 被宏定义为 unsigned long int, 同时 thread 返回线程 ID, attr 用来设置线程的属性, 一般设为 NULL, start_routine 是一个函数指针, 该函数的返回值为 void* , 有一个参数, 参数类型是 void*, 代表着线程需要执行的目标函数, 而arg是用来传给线程启动时候的参数.成功时函数返回值是 0, 失败时返回错误码

6.线程ID和进程ID

    在 Linux 下的线程通常被称为轻量进程, 每一个用户态的线程, 在内核都有与之对应的调度实体, 同时也拥有自己的进程描述符PCB(task_struct)
    在没有线程之前, 一个进程对应一个PCB, 对应一个进程 ID, 当引入线程之后, 每一个用户管辖 N个用户线程, 每一个线程作为一个独立的调度实体都有自己的 PCB, 此时进程和内核的描述符就会编程 1:N, 所有的线程用getpid()获取的进程ID相同, 因此, 为了更好的管理, 就引入了线程组的概念
    多线程进程又被称为线程组, 线程组内的每一个线程都有自己对应的进程描述符(task_struct). 此时的进程 ID表面上看是进程ID, 实际上已经是 tgid了, 而我们所说的 thread-t 类型的ID是用户级别的, 它只在 pthread_t 当前库中有效, 而在内核级别的 线程ID 是一个 pid_t 类型

7. 获取线程ID的方法
#include<sys/syscall.h>
pid_t id;
tid = syscall(SYS_gettid);

    线程组内的第一个线程在用户态被称为主线程, 在内核态被称为 group leader, 内核在创建线程组时, 会将线程组的 id(用户层面的进程id)设置为第一个线程id, group leader 指针指向自身, 即主线程的进程描述符, 所以线程组内存在一个线程id等于用户层面的进程id, 该线程就叫做进程id. 线程组内的其他线程id由内核分配, 线程组的id总是等于主线程的id; 另外必须注意, 进程之间有父进程子进程概念, 而在线程组中所有的线程都是处于对等关系

8.线程ID以及进程地址空间布局

                            这里写图片描述
    上述函数是线程库NPTL提供的用来获取线程自身 id的, 注意该线程id和上述线程 id 不同, 对与Linux实现的 NPTL 线程库而言, pthread_t是一个用户级线程的地址也就是该线程 数据结构的起始地址

9.线程的终止

                            这里写图片描述
    注意,该函数主线程不能调用, 主线程在退出的时候必须以进程方式退出, 其中 retval 是一个输出型参数, 它不能指向一个局部变量, 它必须指向一个全局变量, 或者一个 malloc 分配的, 不能在线程函数栈上分配, 因为当其他线程得到这个返回指针时线程已经退出
                            这里写图片描述
    用来取消线程id是 thread 的线程,成功时函数返回0, 失败时返回错误码

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页