线程

原创 2018年04月17日 11:51:59
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, 失败时返回错误码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41027326/article/details/79972780
收藏助手
不良信息举报
您举报文章:线程
举报原因:
原因补充:

(最多只允许输入30个字)