当前位置: 首页 > news >正文

linux-线程

进程是操作系统分配资源的基本单元。线程是操作系统调度的基本单元。

进程是由线程构成的,每一个进程至少会有一个线程。

线程是在进程的地址空间内运行。线程也需要被管理,但是线程的控制块是被保存在用户区当中的共享区内。

tid就是该线程块的地址。

线程比进程更加轻量化。已初始化和未初始化的全局变量是共享的。

线程在切换的时候,不需要切换进程地址空间这些结构,只需要切换一部分的寄存器和栈,信号表等就可以。线程也有自己的lwp。lwp与pid相同的那个线程被称为主线程,也就是第一个线程。

主线程是主线程栈,在栈空间内,其他每一个线程在共享区有着独立的线程栈。

线程有两种id,一种是只给操作系统内核看的lwp,另一种是用来调用的用户用的tid。

主线程会管理新建立的线程,并且主线程是最后退出的。

线程有独立的寄存器是因为每一个线程的上下文不一样,有独立的栈是因为线程需要单独的执行流。

在cpu内有一部分寄存器,会用来保存该进程高频访问的数据,线程切换的时候,不需要切换这些热数据,而进程切换的时候需要。

而线程也没有进程那样的独立性,一个线程出错,包括该线程的进程也会停止,该进程内的所有线程都不会再执行。

页表。

页表的映射方法。

一个地址有32个bit位。页表将这些bit位分为三组。前10个一组,中间10个一组,最后12个一组。

前10个bit位的组成从0000000000到1111111111,会建立一个数组,这个数组被称为页目录。

这个数组是一个指针数组。每一个指针都指向了中间10个bit位组成的指针数组,而中间的指针数组每一个指针都是指向的物理内存,通过以该物理内存为起点,最后12个bit位为偏移量来找到物理地址。能够通过这种方法找到物理地址是因为物理内存是以page也就是4kb为单位进行存储的。

局部存储

__thread 定义全局变量

局部存储是线程的全局变量。

创建线程

 第一个参数是实际上是一个无符号长整数,是一个输出型参数,会把线程tid带回来。第二个参数是关于设置的直接输入nullptr即可,第三个参数是一个函数指针,是线程调用的入口,这个函数里会写让新创建的线程做什么,第四个是需要传给第三个参数的一个函数参数,有的话设置,没有有输入nullptr。

线程将线程的函数指向完之后,就直接退出了。 

返回0表示成功,失败会返回错误码,不会设置errno。

查看lwp

ps -aL

线程等待

 第一个参数是一个整数,是线程的tid,第二个参数是一个void类型指针的地址,是一个输出型参数,会把线程创建时,所调用的那个函数的返回值带出来。

线程终止

哪个线程调用的就终止那个线程,参数是该线程的返回值。

线程取消

线程被取消,参数是tid,那么返回值不是线程函数的返回值,而是直接返回-1. 

线程分离

线程分离可以让那些不需要主线程关心线程返回值的那些线程,可以自动释放对应的数据块,不需要进行线程等待。

但就算全部线程分离,主线程也要最后退出。

线程的同步和互斥

多线程可能会出现调用同一个函数的情况,有可能会导致数据的不一致问题,那么就需要上锁

pthread_mutex_t是一个语言的自定义类型。 

destroy是将这个锁回收 

init是将这个参数初始化,第二个参数nullptr就行

仅可以对全局变量或静态的pthread_mutex_t类型进行用宏赋值,这个操作后,不需要手动释放,也不需要初始化。

上锁和解锁

参数是定义的锁变量

lock是上锁

trylock是上锁后申请资源失败就返回

unlock是解锁

在上锁和解锁中间的那一块区域被称为临界区域,临界区域要尽量小。

锁本质上是多线程争取唯一的资源,谁先抢到哪个线程就能够在临界区域执行,其他线程会被阻塞,但在执行的线程解锁后,对锁的争夺力要比其他线程强,所以可以对线程进行排列保证线程都能在锁执行。对其他线程来说,这块区域是原子性的。

线程在临界区域时也会被切换, 但是是因为持有着锁被切换的,所以其他要访问这块临界区的线程是无法进入的。

上锁和解锁也可以通过定义一个对象来解决。

这个对象的类构造是上锁,析构是解锁。

将这个对象的生命周期设置为需要上锁的范围就可以。 

原子性:

原子性是只有两种状态的意思,只有一条汇编语句就是具有原子性,那么对其他线程来说,上锁的这块区域就是原子性的,要么有线程在执行,要么没有线程执行。

锁的申请

锁的申请是原子性的,也是被所有线程所共享的,所以锁必须是原子性的,不然可能出现多个线程申请到锁的情况。

申请锁是线程的上下文与共享区内的一个数据进行交换,线程的上下文是0,共享区内是1.只用一条汇编语句让0与1交换,1交换到线程上下文,0交换到共享内存。当其他线程想来交换时,只会交换到0.而这个1就是能否在临界区域进行运行的钥匙,其他线程是0,会被条件阻塞在临界区域外。

在持有锁的线程执行好后,会重新在内存mov1进去。

条件变量

pthread_cond_t是内置的结构体。是条件变量的结构体。

init是对这个结构体进行初始化。

destroy是对这个结构体进行销毁。

如果是全局变量或者静态变量,可以直接用宏定义,就不需要调用初始化和销毁函数了。

线程休眠

 第一个参数是条件变量,是调用的那些线程在该条件变量休眠排序,第二个参数是调用函数所在的锁。

休眠函数调用一定是要在锁里面,因为需要判断,判断是临界区域,所以需要在锁(临界区域)内。而哪个线程调用哪个线程休眠。

调用这个函数的时候,会将线程休眠,并将锁释放,这样就可以让其他线程也可以到临界区域内,调用这个函数,也进行休眠。

线程唤醒

broadcast是直接将休眠在该条件变量内的所有线程都唤醒一次。

signal是将其中一个线程唤醒一次,一般是第一个线程,之后在排到环境变量的最后面。 

信号量的申请

信号量也是一个数据结构 ,通过接口来进行申请和释放信号量的操作。

进行初始化,sem_t是信号量的数据结构类型,第二个参数属性参数输入0就行,第三个参数是初始化时信号量的个数。

释放这个信号量

对该信号量进行p操作,也就是减少一个信号量。

 

对信号量进行v操作,也就是增加一个信号量


http://www.mrgr.cn/news/79398.html

相关文章:

  • ISP(Image Signal Processor)——HDR技术总结
  • 【Flux.jl】 卷积神经网络
  • Motionface RTASR 离线实时语音识别直播字幕使用教程
  • 【PyTorch】动态调整学习率 torch.optim.lr_scheduler.StepLR 调度器
  • 图解大模型分布式训练:流水线并行
  • qt QCommandLineParser详解
  • Ubuntu操作系统在Vmware中的安装、常用操作、最基础的知识、imx6ll基本开发环境配置
  • pushgateway HA高可用方案
  • MVC基础——市场管理系统(一)
  • node.js中跨域请求有几种实现方法
  • 智慧商城项目(vue核心技术与实战)
  • 进入保护模式
  • 【Linux】防火墙
  • 代码随想录算法训练营day50|动态规划12
  • Codeforces Round 991 (Div. 3)
  • 【C语言】C语言的变量和声明系统性讲解
  • 重磅更新:CnosDB 2.3.5.4 版本上线, 性能提升,问题修复一网打尽
  • 吉他初学者学习网站搭建系列(9)——如何用coze做一个网站助手
  • 事件循环(eventloop)
  • PySpark3.4.4_基于StreamingContext实现网络字节流中英文分词词频累加统计结果保存到数据库中
  • 游戏引擎学习第36天
  • Spring事务实现原理
  • 公共云提供商正在错失人工智能机遇
  • Linux 进程 ID(PID)查看 / 获取
  • 在做题中学习(77):快排
  • 万物可爬(以爬取浏览器井盖图片和豆瓣电影名字为例)