linux与线程

2023-11-18

1.1.1 进程

​ 在早期,人们都是为特定机器编写程序,并在其上运行计算任务(task)。渐渐的人们发现CPU与IO设备之间速度差太多了,往往CPU都在空转,是不是可以在CPU空闲的时候做些其他事呢?于是,就有了多任务(每个任务就是一个进程),有了资源调度,有了操作系统...

​ 进程是资源管理的最小单位,操作系统在分配资源(内存,文件等)时是以进程为单位划分的。在单CPU(单核)的时代,通过对多个进程的调度(分配CPU时间片),我们已经可以边听音乐,边打游戏了!

在以前进程被描述为资源分配和执行调度的最小单位,但现在都不这么说了,因为引入了线程的概念。不管怎样,这些都只是一个名称而已,本质上还是要看资源是怎么分配和管理的。

​ 本文不会讨论进程的调度算法,如FCFS,SJF,时间片轮转等。在这里,具体看一下Linux进程的数据结构,以及状态转换:

  • 进程的数据结构

 

 

 

linux进程是一个双端链表结构,其主要内容包括代码段,数据段,堆,栈,内存映射表等

  • 进程的状态转换

 

 

 

进程状态主要在就绪,执行,等待,每一次切换伴随着一次上下文切换。

  • 上下文切换

    进程的上下文包括进程在执行时,CPU所有寄存器中的值、进程的状态以及堆栈中的内容。所谓进程切换即一个进程获得或者丢失CPU时间片,这个过程由内核负责保存进程的状态快照(上下文),由此发生了上下文切换。可以看到这个过程本身就需要消耗很多CPU时间片。

总结: 虽然通过多进程调度,可以并发的处理任务,但可以看到进程的切换很频繁。一个进程刚得到CPU资源就又可能因为发生了IO阻塞而转入等待状态。一个进程在得到CPU时间片后如何充分利用它呢?于是又引入了线程的概念。

1.1.2 线程

​ 为了最大效率的利用CPU,防止IO操作阻塞整个进程运行,降低进程上下文切换的开销,于是又引入了线程的概念,将线程作为CPU调度执行的基本单位。如果一个进程包含多个线程,则这多个线程可以并发或并行执行,并且线程不会导致进程的阻塞(理想情况或者理论层面来讲)。

​ 为什么线程可以降低开销呢?对照上面进程内存结构图,进程的所有线程共享进程的数据结构,除了线程私有的像程序计数器,栈空间,寄存器之外。一个进程的线程之间切换不会发生系统调用,还有采用多线程可以更好的利用多处理器并行计算,线程直接通信更方便等等。

​ 尽管线程有很多优点,但这都只是概念性的。并不是所有的操作系统都支持线程。windows原生支持了线程的实现,但linux中并没有线程的概念,所以只能通过在内核外实现多线程,根据线程的支持是在内核还是内核外,把线程划分为内核线程和用户级线程。

1.1.3 Posix线程标准

​ 在讲Linux下线程实现之前,有必要先介绍一下posix线程标准。POSIX(Portable Operating System Interface)是一套接口API规范,有C语言描述,使用posix API编写的代码在遵循posix规范的平台间是可以移植的,JVM在linux系统上使用的就是pthread线程库作为底层实现。其中关于线程的API被称作pthread,该标准定义了从线程创建,通信,退出全部相关API(以pthread_开头)及其行为约束。

主要API:

函数前缀 功能
pthread_ 线程本身及相关函数
pthread_attr_ 线程属性对象
pthread_mutex_ 互斥锁
pthread_mutexattr_ 互斥锁属性对象
pthread_cond_ 条件变量
pthread_condattr_ 条件变量属性对象
pthread_key_ 线程私有数据
pthread_rwlock_ 读写锁
pthread_rwlockattr_ 读写锁属性对象
pthread_barrier_ 屏障
pthread_barrierattr_ 屏障属性对象
pthread_spin_ 自旋锁

使用时引入头文件#include <pthread.h>:

//--------------------线程相关API--------------------//

/** 创建线程 */
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine)(void*), void *arg);
/** 等待线程结束 */
int pthread_join (pthread_t thread, void**value_ptr);
/** 退出线程 */
void pthread_exit(void *value_ptr);
/** 脱离线程: 将线程属性的分离状态设置为 detached,等待结束时回收资源 */
int pthread_detach (pthread_t thread);
/** 结束线程: 给线程发送中止信号 */
int pthread_kill(pthread_t thread, int sig);
/** 获取线程ID */
pthread_t pthread_self(void);

//----------------线程属性相关API-------------------//

/** 设置线程属性,pthread_create会用到 */
int pthread_attr_init(pthread_attr_t *attr);
/** 销毁线程属性 */
int pthread_attr_destroy(pthread_attr_t *attr);

//----------------互斥锁相关API--------------------//

/** 初始化互斥锁对象 */
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
/** 销毁互斥锁对象 */
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
/** 获取互斥锁(阻塞方式) */
int pthread_mutex_lock(pthread_mutex_t *mutex);
/** 获取互斥锁(非阻塞方式) */
int pthread_mutex_trylock(pthread_mutex_t *mutex);
/** 释放互斥锁 */
int pthread_mutex_unlock(pthread_mutex_t *mutex);

//----------------条件变量相关API------------------//

/** 初始化条件变量 */
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
/** 销毁条件变量 */
int pthread_cond_destroy(pthread_cond_t *cond);
/** 在条件变量上阻塞等待 */
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
/** 在条件变量上有时限等待 */
int pthread_cond_timedwait(pthread_cond_t *cond, 
    pthread_mutex_t *mutex, const struct timespec *abstime);
/** 唤醒一个在条件变量上等待的线程 */
int pthread_cond_signal(pthread_cond_t *cond);
/** 唤醒全部在条件变量上等待的线程 */
int pthread_cond_broadcast(pthread_cond_t *cond);

//----------------线程私有数据相关API------------------//

/** 设置线程私有数据 */
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
/** 删除线程私有数据 */
int pthread_key_delete(pthread_key_t key);

//----------------读写锁相关API------------------//

/** 初始化一个读写锁 */
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
/** 销毁读写锁 */
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
/** 读锁定(阻塞) */
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
/** 读锁定(非阻塞) */
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
/** 写锁定(阻塞) */
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
/** 写锁定(非阻塞) */
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
/** 释放读写锁 */
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

//----------------屏障相关API------------------//

/** 初始化一个屏障(栅栏) */
int pthread_barrier_init(pthread_barrier_t *barrier,const pthread_barrierattr_t *attr,        unsigned count);
/** 销毁屏障 */
int pthread_barrier_destroy(pthread_barrier_t *barrier);
/** 在屏障上等待 */
int pthread_barrier_wait(pthread_barrier_t *barrier);
复制代码

这里只列出了部分API,更多API可以使用man命令查看手册,熟悉pthreads api对理解java线程机制也很有帮助。

1.1.4 Linux线程支持

​ Linux中没有内核级线程的实现,所以只能在用户级别实现线程功能。比较著名的有早期的LinuxThreads,后来的NGPT以及NPTL。这些实现都利用了Linux提供的轻量级进程功能。

​ 轻量级进程(LWP)就是对一个进程的拷贝(clone()系统调用),不过在进行拷贝时,可以有选择的只拷贝部分,clone底层调用内核do_fork方法:

int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, 	unsigned long stack_size)
复制代码

clone_flags就是要拷贝的内容,如LinuxThreads创建线程时,用CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND指定拷贝进程内存空间,文件目录,打开的文件表,信号处理器,注意,这里的拷贝表示在新的进程task_struct中将相关部分地址设置为与原进程相应地址相同,其实是共享相同内存,这个消耗相对普通进程会低一些。可以看到轻量级进程与线程非常相似,共享进程内存空间,打开的文件列表,信号等,也有自己私有的寄存器,栈空间等,但不能就此将轻量级进程与线程等同。

  • LinuxThreads

    LinuxThreads通过创建一个轻量级进程来创建一个线程,即一对一的线程模型,这样,线程的调度有os负责,而LinuxThreads通过一个管理线程(用户级)来管理像线程取消、线程间的同步的工作。通过这种方式模拟了一个进程包含一组线程的定义,但毕竟是模拟的,必然存在很多问题,如管理线程增加了线程创建的开销,线程数受到os进程数限制(后来linux版本有改进),无法利用SMP,线程间通信需要通过信号量的方式等等,以及与posix严重不兼容问题,正是由于种种问题,出现了一些其他新的线程库实现。

  • NGPT

    NGPT(Next-Generation POSIX Threads)是由IBM开发的一套新的用于取代LinuxThreads的线程库,不过并没有被广泛使用,现在已经不在维护了。

  • NPTL

    NPTL(Native POSIX Thread Library)是由Red Hat开发的另一套用于取代LinuxThreads的线程库。NPTL 不在使用管理线程,使用内核支持的进程共享信号及信号处理器,通过共享内存上实现futex功能来做线程同步,以及可以利用SMP特性等,理论上提高了多线程的性能,还有一个重要的点,基本支持posix标准。

    现在大部分平台线程库都是NPTL,可以通过getconf GNU_LIBPTHREAD_VERSION命令查看。

总结: 因为Linux没有原生语义的线程支持,所以在linux平台的线程都是使用轻量级进程来实现线程,这种方式是即有核外也有核内参与,在核内通过轻量级进程模拟,在核外实现线程语义(线程组,线程通信等)在一些地方称之为“混合式线程实现”。总而言之,可以知道,在linux平台一个线程就是一个轻量级进程。


作者:反认他乡是故乡
链接:https://juejin.cn/post/6844903997434757133
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux与线程 的相关文章

  • 手把手教你搭建国产嵌入式模拟器SkyEye开发环境

    SkyEye介绍 SkyEye是一个开源软件 OpenSource Software 项目 中文名字是 天目 SkyEye的目标是在通用的Linux和Windows平台上实现一个纯软件集成开发环境 模拟常见的嵌入式计算机系统 这里假定 仿真
  • 9个Linux 查看系统硬件信息命令(实例详解)

    在Linux下 我们精要遇到需要查看系统的硬件信息 这里我罗列了查看系统硬件信息的实用命令 并做了分类 实例解说 执行环境 ubuntu 16 04 1 cpu lscpu命令 查看的是cpu的统计信息 root ubuntu home p
  • Linux离线安装Git

    Linux环境下离线安装git 简介 本文为lunix 系统下离线安装git 如有安装过git 请先删除git相关文件 centos Unbantu 等平台的安装方式略有不同 复制代码 原文链接 Git官网 下载Git 解压文件 tar v
  • 怎样查看Linux服务器配置

    1 前言 本文主要讲解如何查看Linux服务器配置 主要是查看服务器硬件配置 怎样查看Linux服务器配置 2 查看CPU信息 2 1 使用 lscpu 命令查看服务器CPU信息 lscpu 如下图 使用lscpu命令查看服务器CPU信息
  • 常用adb命令整理

    一 adb介绍 adb Android Debug Bridge Android 调试桥的缩写 adb 是一个 C S 架构的命令行工具 主要由 3 部分组成 运行在 PC 端的 Client 可以通过它对 Android 应用进行安装 卸
  • Linux 网卡重新获取IP

    1 所有网卡驱动重新加载 service network restart 2 对单一网卡进行操作 ifconfig a 获取所有网卡信息 可以看到所有网卡的名字 ifconfig 网卡名称 down ifconfig 网卡名称 up 3 D
  • Linux 文件权限

    简介 在 Linux 的学习过程中 文件权限是一个很重要的概念 毕竟 Linux 中的各种操作都离不开权限的支持 这篇博客算是对 Linux 文件权限学习的一个简单总结 用户与用户组 Linux 的文件权限是和 用户与用户组 密切相关的一个
  • 一款运行于windows上的linux命令神器-Cmder(用过后爱不释手)

    一 前言 很多工程师都习惯了使用linux下一些命令 再去用Windows的 cmd 简直难以忍受 要在windows上运行linux命令 目前比较流行的方式由 GunWin32 Cygwin WSL Bash on Windows Git
  • linux搭建ftp

    ftp一些概念了解 Linux安装vsftpd及配置详解 1 安装 yum y install vsftpd 2 FTP主动模式与FTP被动模式 3 防火墙开启21端口 文中是使用iptables开启的 现在centos7 2版本默认是防火
  • Let's Encrypt 泛域名证书申请

    github https github com Neilpang acme sh 通过acme申请Let s Encrypt证书支持的域名DNS服务商有以下这些 国内用户较多的 cloudxns dnspod aliyun 阿里云 clou
  • Linux内存占用分析的几个方法,你知道几个?

    0 引言 系统内存是硬件系统中必不可少的部分 定时查看系统内存资源运行情况 可以帮助我们及时发现内存资源是否存在异常占用 确保业务的稳定运行 例如 定期查看公司的网站服务器内存使用情况 可以确保服务器的资源是否够用 或者发现服务器内存被占用
  • 多个项目引用,如何打包项目成为war,jar包

    原文链接 多个项目引用 如何打包项目成为war jar包 推荐导入项目 IDEA如何导入多个maven项目在pox引入自建包 那么我们导入了多个项目的依赖关系后 随之而来产生多个项目 那我们打包的时候 应该如何将其建在一个war或war包
  • [ERROR] Can't open the mysql.plugin table. Please run mysql_upgrade to create it.(入职小灰)

    mariadb剧本安装后自动重启不了 飞要一次手动重启 这对于重要业务来说是致命的 今天遇到的错误 ERROR Can t open the mysql plugin table Please run mysql upgrade to cr
  • 在Ubuntu 16.04 LTS服务器上安装FreeRADIUS和Daloradius的方法

    FreeRADIUS 为AAA Radius Linux下开源解决方案 DaloRadius为图形化web管理工具 freeradius一般用来进行账户认证管理 记账管理 常见的电信运营商的宽带账户 上网账户管理 记账 都是使用的radiu
  • 如何重置或破解Ubuntu 20.04的用户密码

    1 前言 本教程主要讲解如何破解Ubuntu 20 04 Linux root密码或普通用户密码 在本教程中 您将学习到以下知识 如何重置root用户密码 如何挂载根目录读写 如何重置普通用户密码 实施准备工作 Ubuntu 20 04系统
  • Linux Top 命令指南

    top 命令允许用户监视 Linux 上的进程和系统资源使用情况 它是系统管理员工具箱中最有用的工具之一 并且在每个发行版中都预装了它 与 ps 等其他命令不同 它是交互式的 我们可以浏览进程列表 终止进程 等等 本文中 我们将了解如何使用
  • 华为云云耀云服务器L实例评测

    大家好 我是雄雄 欢迎关注微信公众号 雄雄的小课堂 目录 前言 效果图 购买云耀云服务器L实例 重置密码 放开端口 远程连接 安装云监控面板 进入监控面板 前言 有幸参与了华为云云耀云服务器L实例的评测名额 借着评测 顺便教给大家一项技能
  • nginx重启命令

    nginx s reload 修改配置后重新加载生效 nginx s reopen 重新打开日志文件 nginx t c path to nginx conf 测试nginx配置文件是否正确 关闭nginx nginx s stop 快速停
  • Linux 基础知识

    一 从认识操作系统开始 1 1 操作系统简介 我通过以下四点介绍什么操作系统 操作系统 Operation System 简称OS 是管理计算机硬件与软件资源的程序 是计算机系统的内核与基石 操作系统本质上是运行在计算机上的软件程序 为用户
  • linux与线程

    1 1 1 进程 在早期 人们都是为特定机器编写程序 并在其上运行计算任务 task 渐渐的人们发现CPU与IO设备之间速度差太多了 往往CPU都在空转 是不是可以在CPU空闲的时候做些其他事呢 于是 就有了多任务 每个任务就是一个进程 有

随机推荐

  • linux内存利用率计算方式

    一 查看内存的方式 root vmware free h root vmware cat proc meminfo 需要使用的指标有 MemTotal MemFree Buffers Cached MemTotal 总内存大小 MemFre
  • 计算半圆弧的周长及半圆的面积

    3 计算半圆弧的周长及半圆的面积 编程并输出半径r 5 3的半圆弧长 提示 半圆弧长不应该加直径的长度 及该半圆弧与直经围成的半圆的面积 的取值为3 14159 要求半径r和必须利用宏常量表示 include
  • MacOS怎么查看进程占用内存是多少

    一 背景 在Linux下可以使用 free 命令来方便的查看内存占用情况 如 free g free m等 但MacOS下没有这个命令 既然如此 那么MacOS里是否有类似的工具呢 而我们又该如何查看整个PC的内存占用情况 及指定进程的内存
  • 慢慢欣赏linux pud_offset解析

    typedef struct pudval t pud pud t gt typedef u64 pudval t dir表示L0页表索引的指针 指向PUD页表的基地址 define pud offset dir addr pud t va
  • 《计算机工程》期刊 从投稿到录用过程

    本人 18级双一流院校全日制研究生在读 专业 地理学 研究方向 激光雷达数据处理与三维点云语义分割 文章投计算机工程期刊从投稿到可刊总周期 两个月之内 审稿费100元 可加急 发表情况 预计十月发表 期刊选择 论文修改完成之后 自己有上网了
  • 教你利用IBM的开发手册

    在IBM AIX下做开发的不少人一直都不知道IBM其实已经提供了详尽的开发文档及手册供开发人员使用 很多人仍然使用很原始的方式 例如在GOOGLE中搜索 或者买本手册型的书放在边上 更有甚者直接记在脑子里 这算是相当聪明的了 但是 有许多与
  • 山石发声

    技术变化快 投入不可控 攻击侧升级 攻防不对等 人才缺口大 维护成本高 山石网科安全运营体系 让安全运营挑战迎刃而解 近年来 全球安全服务市场景气度较高 行业增速远高于安全行业的整体水平 究其原因 首先是IT基础架构的变化驱动安全服务体系的
  • java每日一题:手动触发垃圾回收(GC)

    面试官 首先 我想问一下 你能向我解释一下 手动触发Java垃圾回收 的过程吗 面试者 在Java中 垃圾回收是自动进行的 由Java虚拟机 JVM 负责管理 但是 有时候我们可能希望手动触发垃圾回收以释放一些无用的对象 这可以通过调用Sy
  • Scrapy的基本介绍、安装及工作流程

    一 Scrapy介绍 Scrapy是什么 Scrapy 是用 Python 实现的一个为了爬取网站数据 提取结构性数据而编写的应用框架 异步爬虫框架 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫 抓取指定网站的内容或图片 Scr
  • 程序员搜索技巧

    1 搜索时 一定使用关键字搜索 空格 浓缩减少废话与口语 不断负反馈增添修改关键词 再不行就英文 2 精确搜索 作为整体 用 双引号 3 查找标题含有的确定关键词 intitle 英文冒号 4 站内搜索 过滤垃圾广告 定位某一网址答案 xx
  • Cobertura 统计多模块maven项目测试覆盖率

    Cobertura 统计单元测试覆盖率的机制 运行类 并在一个log文件中记录哪一行被执行 然后将源代码和log文件进行比对 1 简单的情况 单模块maven项目 项目结构 源代码 src main java se sigma calcul
  • OpenCV图像人脸检测及视频中的人脸检测(附源码)

    文章目录 一 数据和知识准备 1 下载HAAR与LBP数据 2 opencv相关知识 二 python opencv实现人脸检测 1 图像单人脸检测 2 图像多人脸检测 3 视频中人脸检测 4 摄像头人脸检测 一 数据和知识准备 1 下载H
  • java中的垃圾回收机制

    概述 JAVA中的垃圾回收机制是自动的 它是保证程序健壮的主要手段 同时也避免了回收内存带来的代码繁琐 注意 1 java中的垃圾回收机制采用的是多线程技术实现的 垃圾回收功能是一条优先级比较低的线程 2 垃圾回收机制仅仅作用于堆内存 和栈
  • Unity一些很有用的技巧

    一 性能 多线程射线检测 在使用中经常需要每帧进行射线 性能消耗比较大 那么可以使用Unity Collections RaycastCommand进行多线程的检查 将耗能操作放到子线程去 同样其他的形状检测 Unity官方文档 Rayca
  • Python每日一记196>>>pandas.core.indexing.IndexingError: Too many indexers

    以下代码出现了pandas core indexing IndexingError Too many indexers问题 import pandas as pd import numpy as np data 2018 pd read e
  • Rust组合器

    组合器 在 Rust 中 组合器更多的是用于对返回结果的类型进行变换 例如使用 ok or 将一个 Option 类型转换成 Result 类型 下面我们来看看一些常见的组合器 or 和 and 跟布尔关系的与 或很像 这两个方法会对两个表
  • JAVA 8 junit 单元测试——静态方法单元测试 Mockito.mockStatic

    静态方法的单元测试Mockito 直接上例子 方法 public ArrayList
  • 深度缓冲详解(DepthBuffer)

    参考出处 1 OpenGL 深度缓冲区 Z缓冲区 介绍 2 什么是深度缓冲 Depth Buffer 1 深度缓冲概念 深度缓冲区与帧缓冲区相对应 用于记录上面每个像素的深度值 通过深度缓冲区 我们可以进行深度测试 从而确定像素的遮挡关系
  • VMware安装流畅系统Chrome OS以及国产系统FedyOS(基于Chrome OS的二次开发)

    一 序言 VMware 版本 15 5 6 物理机型号 芯片类型不限制 不向之前发布的vmware安装Mac OS篇 想看的点击这 二 链接资源 Chrome OS CloudReady Home v83 x64 点击进入 提取码 yyds
  • linux与线程

    1 1 1 进程 在早期 人们都是为特定机器编写程序 并在其上运行计算任务 task 渐渐的人们发现CPU与IO设备之间速度差太多了 往往CPU都在空转 是不是可以在CPU空闲的时候做些其他事呢 于是 就有了多任务 每个任务就是一个进程 有