Linux线程概念和控制

目录

前言

一.线程概念

线程与进程的区别

线程优点

线程调度优势

pthread库

二.线程控制

线程创建

线程等待

获得自身tid

线程分离

线程退出


前言

        Linux线程是一种轻量级进程,是操作系统调度的基本单位。线程是进程中的一个执行路径,多个线程共享进程的资源,  理解线程有利于我们编写多执行流代码

一.线程概念

进程是系统分配资源的基本单位,  线程是调度的基本单位,  我们先来看进程与线程的关系

        一个进程可以有多个PCB,  这些PCB共用一个虚拟地址空间,  想要一个进程有多个执行流,  只需要创建多个PCB指向这个虚拟地址空间,  CPU按照时间片轮转调度这些属于一个进程的PCB,  在外界看来就是并发运行

        线程是进程的一个执行流,  一个进程至少有一个执行流,  线程共享进程的资源,  上面属于同一个进程的PCB就是一个个线程

线程与进程的区别

  • 拥有资源 : 进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。
  • 调度: 线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
  • 系统开销 : 由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。
  • 通信方面 : 线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC

线程优点

  • 创建一个新线程的代价要比创建一个新进程小得多, 线程不需要复制整个进程的内存空间,只需分配少量的资源,如独立的栈和线程控制块(TCB)
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多,  进程切换要切换地址空间和大部分资源,  而线程切换只需保存自己独立的硬件上下文数据
  • 线程占用的资源要比进程少很多
  • 能充分利用多处理器的可并行数量
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务,  I/O密集操作太多时间都在等
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

线程调度优势

我们先来看一个概念 :  缓存命中

Cache是计算机系统中的一种高速存储器,用于在处理器与主存(RAM)之间暂存频繁访问的数据

  • 缓存命中(Cache Hit):当处理器访问的数据已经在缓存中时,称为缓存命中。这种情况下,处理器可以直接从缓存中获取数据,极大地提高了访问速度。
  • 缓存未命中(Cache Miss):当处理器访问的数据不在缓存中时,称为缓存未命中。此时,数据需要从主存或更低级别的缓存中加载到缓存中,增加了访问延迟。

缓存局部性:  

  • 时间局部性(Temporal Locality):程序倾向于在短时间内反复访问相同的内存位置。线程调度如果能够在相对短的时间内再次调度同一线程,则该线程的内存数据很可能仍然保留在缓存中,从而提高缓存命中率。
  • 空间局部性(Spatial Locality):程序倾向于访问相邻的内存位置。如果线程调度能保持线程在同一核心上运行,并且访问相邻内存区域的数据,这些数据更可能已经在缓存中,减少缓存未命中。

        线程进行调度时,  因为这些线程属于同一个进程,  共享虚拟地址空间,  所以Cache可能已经缓存了其他线程的数据,  调度一个进程的其他线程的时候,  如果已经缓存了该线程数据,  就不需要刷新缓存,  直接访问缓存中的数据,  提高了访问速度

pthread库

        在Linux中操作系统没有对线程进行专门的封装,  认为线程是一种轻量级进程,  可以复用进程的接口,  pthread库封装了这些接口,  并对创建的线程做管理,  对外提供线程的可视化概念

        pthread库是一个动态库,  也就是说它可以加载到任意进程的地址空间中,  统一管理所有使用这个库创建的线程,  (在之前的博客中已经介绍过进程地址空间和动态库的原理)

二.线程控制

线程创建

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                    void *(*start_routine) (void *), void *arg);

参数

        thread:  输出型参数,  输出创建线程的TID, 用来标识唯一一个线程, 后面的操作都依靠这个

        attr:  线程的属性,  可以控制线程的栈大小,  调度策略等属性,  NULL表示默认

        start_routine:  线程要执行的函数

        arg:  给线程执行的函数传参

返回值

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

线程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

thread :  创建线程时获取的线程标识符

retval :  输出型参数,  线程执行的返回值

pthread_join  会进行阻塞等待

下面这个例子演示了线程创建和传参和等待

void *headler(void *args)
{
    int num = (int *)args;

    while(num)
    {
        cout<<num<<endl;
        num--;
    }
 
    return nullptr;
}

int main()
{
    pthread_t tid;
    int num=10;
    pthread_create(&tid, nullptr, headler, (void *)&num);

    pthread_join(tid,nullptr)

    return 0;
}

获得自身tid

#include <pthread.h>
pthread_t pthread_self(void);

线程分离

#include <pthread.h>
int pthread_detach(pthread_t thread);

        如果不想考虑一个线程的执行结果,  就可以使用这个接口让指定的线程分离,  这个线程结束会自动回收

        线程分离后, 不能进行join, 会发生错误

线程退出

#include <pthread.h>
void pthread_exit(void *retval);

让线程提前退出,  返回值通常让pthread_join接收

注意 : exit函数用于进程退出,  进程退出了,  所有线程也退出了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值