1. 线程概念
  2. 线程与进程
  3. 线程间的独有与共享
  4. 多线程与多进程
  5. 线程控制

线程概念

什么是线程

线程是进程中的一条执行流,执行程序中的某部分代码。linux下没有具体实现的线程,只有库函数用pcb来实现的线程,所以可以认为,每个pcb就是一个线程,所以进程中都至少有一个线程,这些PCB共用进程中的同一个页表和虚拟地址空间,比传统的进程更加轻量化,所以这些线程在linux下也被称为轻量级进程

PCB也就是进程控制块,在Linux下PCB可以实现对程序的调度运行,所以可以将其作为一个执行流,来实现线程

为什么要使用线程呢?
  1. 创建一个新线程的代价要比创建一个新进程小得多
  2. 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  3. 线程占用的资源要比进程少很多

线程与进程

线程与进程

进程:是一个程序的动态执行,是系统资源分配的基本单位
线程:线程是进程中的一条执行流,是CPU调度的基本单位

我之前博客提到的进程其实都是单线程的进程,在linux其实每个pcb就可以理解为一个执行流,也就是一个线程


从这两幅图可以看出来,linux下的进程其实是一个线程组,一个进程中可以包含多个线程,每一个线程都是进程中的一条执行流(PCB),这些线程在进程的内部运行,本质也就是在进程的虚拟地址空间中运行

线程之间共用进程中的同一个虚拟地址空间,通过同一个页表来完成映射


线程间的独有与共享

既然线程都处于同一个进程中,共用同一个虚拟地址空间和页表,那么它们之间还有哪些数据共享,哪些数据独有呢?

独有:
  • 标识符(唯一的标识符来区分线程)
  • 栈(独有的函数栈,防止调用栈紊乱)
  • 寄存器(也就是PCB中的上下文数据,程序计数器,内存指针等)
  • 信号屏蔽字(因为信号会打断进程当前操作,让他优先处理信号,但是一个信号只需要一个执行流去执行即可,如果不想该线程被打断,则对该信号屏蔽,让其他线程去执行)
  • errno(系统调用完毕后重置的一个全局变量,防止被其他线程覆盖)
  • 优先级(各有各的调度优先级)
共享
  • 虚拟地址空间(代码段/数据段, 线程之间数据和代码都共享)
  • 文件描述符表(io信息)
  • 信号处理方式(信号是针对整个进程的,所以处理方式应该都一样)

多线程与多进程

如果需要进行多任务处理,有两种方法,一种是多线程,一种是多进程
多进程

多线程

多线程的优点:
  • 线程的创建和销毁成本低(从上面的图可以看出来,创建多个线程只需要创建多个PCB)
  • 线程间调度成本低(使用同一个页表,调度切换时不用切换页表)
  • 线程间通信更加灵活(共用同一个虚拟地址空间,数据段共享,只需要获取地址即可访问数据)
多进程的优点:
  • 更具有健壮性,更加稳定(因为异常,系统调用,信号等都是对整个进程生效,一旦出现进程出问题会影响所有线程)
共同优点
  • IO密集型程序:多任务并行处理(单磁盘可以并行压缩IO等待事件/多磁盘可以实现同时处理)
  • CPU密集型程序:程序中进行大量的数据运算处理,CPU资源足够,则可以同时处理,提高效率(线程数为CPU核心数+1,多出来的一个是当某一线程阻塞时顶替用的。如果创建进程过多,会增加切换调度的成本)

线程控制

前面也说过了,Linux本身是没有线程的,只有库函数中通过PCB来模拟的线程。在用户态调用库函数创建一个线程,其本质就是在内核中创建一个轻量级进程来实现程序的调度。

创建线程:

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void*),void *arg);

thread:输出型参数,用来获取线程ID–线程的操作句柄
attr:用于设置线程属性,通常置NULL
start_routine:函数指针,线程的入口函数,线程会去运行这个函数,函数运行结束后,线程退出。
arg:需要传递给线程的入口函数的参数
头文件:#include<pthread.h>
返回值:成功返回0,失败返回非0


终止线程:

当线程执行完入口函数就会退出,但也可以通过调用对应的接口退出。

退出一个线程

void pthread_exit(void *retval);

和exit()不同,exit是退出整个进程

线程退出接口,哪个线程调用就退出哪个线程
retval:退出返回值
主线程退出,并不会导致进程退出,只有全部线程退出了进程才会退出。

终止一个线程

int pthread_cancel(pthread_t thread);

线程等待:

线程有一个默认的属性,joinable,处于这个属性的线程,退出后需要被其他线程等待获取返回值并且释放资源。
默认情况下,线程是必须被等待的,如果不等待,则会造成资源泄露

int pthread_join(pthread_t thread, void **retval)

等待指定线程退出,获取其返回值。
并且该函数会阻塞,线程没有退出则一直等待。

线程分离:

将joinable的属性修改为detach属性

joinable:退出后需要被其他线程等待获取返回值并且释放资源。
detach:退出后自动释放资源,不需要被等待

如果不想获取返回值,也不想等待线程退出,就可以使用线程分离

int pthread_detach(pthread_t pthread)

线程id

pthread_t pthread_self(void)

返回调用线程的tid

在这里就要提一提tid与pid的区别,以及对于一个进程,我们看到的进程的pid到底是什么

tid:用户态线程的id,是线程的操作句柄,其实就是线程这块空间的首地址。
pid:轻量级进程id,这就是用来模拟线程的pcb的id
tgid:线程组id,也就是主线程id,就是我们外面看到的进程的pid

Linux 多线程(一)线程概念:线程概念、线程与进程、线程间的独有与共享、多线程与多进程、线程控制相关推荐

  1. 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这

    线程共享的环境: 进程代码段.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯).进程打开的文件描述符.信号的处理器.进程的当前目录和进程用户ID与进程组ID. 进程拥有这许多共性的 ...

  2. java进程与线程_Java多线程笔记(零):进程、线程与通用概念

    前言 不积跬步,无以至千里:不积小流,无以成江海.在学习Java多线程相关的知识前,我们首先需要去了解一点操作系统的进程.线程以及相关的基础概念. 进程 通常,我们把一个程序的执行称为一个进程.反过来 ...

  3. Java多线程笔记(零):进程、线程与通用概念

    前言 不积跬步,无以至千里:不积小流,无以成江海.在学习Java多线程相关的知识前,我们首先需要去了解一点操作系统的进程.线程以及相关的基础概念. 进程 通常,我们把一个程序的执行称为一个进程.反过来 ...

  4. C++11多线程第一篇:并发基本概念及实现,进程、线程基本概念

    文章目录 1.并发基本概念及实现,进程.线程基本概念 1.1 并发.进程.线程的基本概念和综述 1.1.1 并发.并行 1.1.2 可执行程序 1.1.3 进程 1.1.4 线程 1.1.5 程序.进 ...

  5. java 线程的基本概念_Java多线程——多线程的基本概念和使用

    一.进程和线程的基础知识 1.进程和线程的概念 进程:运行中的应用程序称为进程,拥有系统资源(cpu.内存) 线程:进程中的一段代码,一个进程中可以有多段代码.本身不拥有资源(共享所在进程的资源) 在 ...

  6. java 线程的基本概念_Java多线程——基本概念

    线程和多线程 程序:是一段静态的代码,是应用软件执行的蓝本 进程:是程序的一次动态执行过程,它对应了从代码加载.执行至执行完毕的一个完整过程,这个过程也是进程本身从产生.发展至消亡的过程 线程:是比进 ...

  7. java线程的基本概念

    进程和线程 进程的诞生 操作系统中有2个任务A,B,任务A先执行,执行到一半需要io,因此要大量时间,在这个时间段内cpu是空闲的,浪费了资源,于是就有进程,当A暂时无法利用cpu,但是又不能销毁时, ...

  8. 进程和线程的基本概念

    进-线目录 前言 1.为什么会产生进程? 2.进程是什么? 3.为什么会产生线程? 4.多进程可以实现并发,为什么还要使用线程? 5.进程和线程的区别 6.理解上下文切换 前言 程序:指令和数据的集合 ...

  9. 第一章 进程与线程的基本概念

    1.1 进程产生的背景 最初的计算机只能接受一些特定的指令,用户每输入一个指令,计算机就做出一个操作.当用户在思考或者输入时,计算机就在等待.这样效率非常低下,在很多时候,计算机都处在等待状态. 批处 ...

最新文章

  1. es6+的javascript拓展内容
  2. python收入波动告警分析_使用Python/Pandas分析告警日志数据
  3. 手游方舟怎么输入代码_明日方舟再次登顶失败,为了不发十连奖励,鹰角实力控分?...
  4. Oracle数据库连接报错
  5. 网络系统设计综合布线方案
  6. bootstrap table用法
  7. 设置android模拟器的ip地址,设置Android模拟器IP地址
  8. DNA甲基化芯片探针的P值如何计算
  9. 微软历史最高市值是多少?
  10. 在iOS设备上进行抓包(补充)
  11. 蒋建平:国内云计算刚刚起步
  12. vue项目结合iview4UI组件实现树状结构及复杂动态表头列表 Tree-Table 及复杂header 省市区树状表格联动 数据优化后台一次性返回一万条数据页面卡死问题
  13. 令人敬畏的泰格伍兹 万维钢_令人敬畏的桌面壁纸:Windows 7版
  14. 微信小程序页面静态页是html,制作一个微信小程序中的静态页面
  15. 这所“南方小镇”藏着雅居乐陈卓林描绘的“第二人生”
  16. 凸优化——凸优化问题与算法
  17. java中的开方Math.sqrt(n)函数和平方{a的b次方Math.pow(a, b)}
  18. 搜狗输入法简约而美的皮肤推荐
  19. 流信息服务器上,视频流服务器
  20. 两个程序悲催的进化旅程

热门文章

  1. 服务提供者与服务消费者
  2. jvm虚拟机组成部分讲解、jvm虚拟机参数使用讲解并发编程框架篇
  3. 伦茨8400变频器面板按键说明_变频器调试笔记
  4. zsh配置其显示当前文件路径
  5. linux环境下vim创建java文件,并编译运行
  6. JSON数据从OSS迁移到MaxCompute最佳实践
  7. [译文] 初学者应该了解的数据结构: Tree
  8. 跨主机使用 Rex-Ray volume - 每天5分钟玩转 Docker 容器技术(77)
  9. 解决appium安装app时某些手机弹出的提示框
  10. 第16章 C预处理器和C库 16.3 在#define中使用参数