Wilder's Blog.

关于线程的一些总结

字数统计: 2.8k阅读时长: 9 min
2018/04/24 Share

什么是 linux 进程

进程:进程是指正在执行的程序,是程序正在执行的一个实例。当用户下达运行程序的命令后,就会产生一个进程。进程是系统进行资源分配和调度的一个独立单位,也就是说进程具有独立的地址空间,一个进程的崩溃不会影响到其它进程的进行。进程由程序指令、和从文件、其它程序中读取的数据或者用户的输入组成。

​ 可以举一个例子,把程序比作菜单上面的菜,那么制作出这一盘菜需要的料理采购、厨师、调料以及通知服务员上菜这一整个过程就是一个进程。其中采购和调料可以看成数据的读取,厨师炒菜过程看成逻辑处理,通知服务员则看成是通信。

linux中的进程有三个信息,分别是 PID、COMMAND、CMD

  • PID:pid是一个整数,每一个进程都有一个唯一的PID来代表自己的身份
  • COMMAND:进程的简称
  • CMD:进程所对应的程序以及运行时所带的参数

创建一个进程

​ 除了init进程是计算机开机时候系统建立的,其它进程都是通过老的进程复制自身得到,复制之后内存中就会开辟出一片新的内存空间给新的进程。

程序和进程区别

​ 进程是程序的具体实现,同一个程序可以被执行多次,每次都可以在内存中开辟独立的空间来装载,从而产生多个线程。

参考博客:

http://www.jb51.net/article/111091.htm

https://www.kancloud.cn/kancloud/understanding-linux-processes/52208

http://www.techweb.com.cn/network/system/2017-06-24/2545223.shtml

https://blog.csdn.net/laviolette/article/details/51507642

什么是linux线程

​ 我翻查了一些博客,博客上说 linux 对线程的概念并没有 windows 那么清晰

线程概念:线程是进程的实体对象,我将它理解为进程的基本单位,一个进程内会有多条线程并行或者伪并行执行,但是线程本身不拥有系统资源,只拥有一点在运行中不可缺少的资源(程序计数器,一组寄存器和栈),同一个进程内的线程共享进程内的所有资源。

线程与线程之间的通信方式

线程间的通信方式按照我的理解分为两种:

通过共享变量方式进行通信

方法名称 描述
notify() 通知一个在对象上等待的线程,使其从wait()方法中返回,而返回的前提是该线程获取到了对象的锁
notifyAll() 通知所有等待在该对象的线程
wait() 调用该方法会使线程进入waiting 状态,只有等其它线程唤醒或者该线程被中断的时候才会返回,调用wait()方法之后会释放锁
wait(long time) 等待一定的时间自动返回

通过队列来实现线程的通信

​ 一个线程和另一个线程之间通信时,只需要向(处于另一个线程中的)消息队列中发送(或接收)消息,而不必一直等待对方是否响应。

进程间的通信方式

管道

什么是管道?

​ 在 linux 中,管道本质上来说也是一种文件,管道的结构如下(借助了文件系统的file结构和 VFS(不懂这个是什么概念)的索引结点inode,通过将两个file 结构指向同一个临时的VFS索引结点,而这个VFS索引结点又指向一个物理页面实现的)

wKioL1eNaPuQpljkAACa0Cx8ULs732.png-wh_50

管道创建之后的通信:

​ 1、父进程调用 pipe 开辟管道,得到指向两个文件描述符指向管道的两端,一端是读端,一端是写端

​ 2、父进程调用 fork 创建子进程,子进程同样有两个文件描述符指向同一管道

​ 3、父进程关闭管道读端,子进程关闭管道写端。这样父进程可以往管道里写,子进程可以往管道里读,管道是用唤醒队列实现的,数据从写端流入从读端流出,这样就实现了进程之间的通信。

管道的特点:

​ 1、管道只允许具有血缘关系的进程之间进行通信(但是有名管道允许无亲缘关系进程间的通信)

​ 2、管道只允许单向通信

​ 3、依赖文件系统

​ 4、面向字节流

​ 5、管道随进程,进程在管道在,进程消失管道对应的端口也关闭,两个进程消失管道也对应消失

消息队列

什么是消息队列?

​ 消息队列提供了一种从一个进程想另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。消息队列是链表队列,它通过内核提供一个struct msqid_ds *msgque[MSGMNI]向量维护内核的一个消息队列列表,因此linux系统支持的最大消息队列数由msgque数组大小来决定,每一个msqid_ds表示一个消息队列,并通过msqid_ds.msg_first、msg_last维护一个先进先出的msg链表队列。

​ 当发送一个消息到消息队列的时候,把发送的消息构造成一个msg结构对象,并添加到链表队列,同样接收消息是从msg链表队列尾部查找到匹配的msg节点,从队列中删除该msg节点。

消息队列和管道的比较:

1、消息队列进行通信的进程可以是不相关的进程(进程之间没有进程关系,当然命名管道也可以)

2、两者都是通过发送和接收的方式来传递数据

3、消息队列发送数据用msgsnd,接收数据用 msgrcv,管道使用的是read 和 write

4、消息队列可以独立于发送和接收进程而存在,从而消除了管道打开关闭而可能产生的困难

5、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法

参考:https://blog.csdn.net/ljp1919/article/details/52556555

信号量

什么是信号量?

​ 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。在任一时刻只有一个执行线程能够访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。(我把它理解为类似于 锁 的东西)。

​ 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

​ P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行

​ V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

如何进行通信?

​ 当两个进程之间要进行通信的时候,两个进程之间将共享信号量sv,当一个进程执行了P(sv) 操作,它将得到信号量。第二个进程将被阻止进入到临界区而会被挂起等待第一个进程离开临界区域之后释放信号量之后,这时第二个进程才可以恢复执行。

共享内存区

什么是共享内存?

​ 顾名思义,当一个程序想和另一个程序通信的时候,内存会将这两个程序生成一个公共的内存区域。这块被两个进程分享的内存区域叫做共享内存。但是,我们的程序中仅仅有一个进程訪问了共享内存。因此在集中展示了共享内存机制的同一时候。我们避免了让代码被同步逻辑搞得混乱不堪。

为了简化共享数据的完整性和避免同一时候存取数据,内核提供了一种专门存取共享内存资源的机制。这称为相互排斥体或者mutex对象

通过共享区域通信的步骤?

​ 1、获取 mutex 对象,锁定共享区域

​ 2、将要通信的数据写入共享区域

​ 3、释放 mutex 对象

linux 共享内存之间的通信?

这里写图片描述

(linux 共享内存模型说道 内存地址与内存页面之间的映射,不太明白这个是如何进行映射的)

参考博客:https://www.cnblogs.com/blfbuaa/p/7145946.html

https://blog.csdn.net/lfw19891101/article/details/5994927

线程如何切换

线程切换过程:
1.虚拟机启动之后,就进入了解释器的死循环,一直解释执行pc指针对应的java字节码。

  1. 每个现在对应着一个stack,方面调用的时候,会在其上分配栈帧,由sp,fp等指针指向。
  2. 线程调度,其实就是记录下当前线程的pc,sp,fp等指针,并将这几个指针(pc,sp,fp等,都是全局的)指向下一个将要执行的线程的相应位置。
  3. 当恢复上述的几个指针之后,就切换回之前的线程了

java 线程状态的切换?

这里写图片描述

线程所拥有的资源

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.。

一个进程中的所有线程共享该进程的地址空间,但是他们有各自独立的栈

线程共享资源 线程独享资源
地址空间 程序计数器
全局变量 寄存器
打开的文件
子进程 状态字
闹铃
信号及信号服务程序
记账信息

参考博客:https://blog.csdn.net/liukaiyu_ak/article/details/52368303

CATALOG
  1. 1. 什么是 linux 进程
  2. 2. 什么是linux线程
  3. 3. 线程与线程之间的通信方式
    1. 3.1. 通过共享变量方式进行通信
    2. 3.2. 通过队列来实现线程的通信
  4. 4. 进程间的通信方式
    1. 4.1. 管道
    2. 4.2. 消息队列
    3. 4.3. 信号量
    4. 4.4. 共享内存区
  5. 5. 线程如何切换
  6. 6. 线程所拥有的资源