操作系统——多进程

这篇博客探讨了操作系统中的进程同步与互斥概念,包括进入区、临界区、退出区和剩余区,强调了互斥访问的四个原则,并介绍了几种互斥访问算法,如单标志法、双标志先检查和Peterson算法。接着,文章讲解了信号量的类型,如整数型和记录型信号量,以及它们如何确保资源的正确分配。最后,管程作为简化信号量管理的工具被提出,其特点是保证同一时间只有一个进程在管程内操作。

进程同步与互斥

有时并发的几个进程为了完成某个任务,需要按一定顺序先后进行操作,这种顺序就是直接制约关系,又叫进程同步。在同步操作时,多个进程需要访问同一个资源,这个资源叫临界资源。一个进程访问临界区时,其他进程都无法访问,这叫间接制约关系,也叫互斥。
互斥访问临界资源代码的组成部分:

  • 进入区:负责检查能否进入临界区,如果可以,就设置正在的访问的标志,可以理解为加锁。
    临界区:访问临界资源并操作数据的代码段。
  • 退出区:解除正在访问临界区的标志,可以理解为解锁。
    剩余区:其他操作。

互斥访问的原则:

  • 空闲让进:临界区没有进程时,可以允许请求访问临界区的进程访问。
  • 忙则等待:如果有线程在访问临界区,其他线程必须等待。
    有限等待:进程等待的时间必须是有限的。
  • 让权等待:如果进程无法访问临界区,那么就得释放处理机。
    互斥访问算法:
  • 单标志法:设计一个“标志”,是布尔型变量,如果想访问临界区就设为true。在进入区只检查标志,不进行上锁。违反了忙则让进原则。
  • 双标志先检查:标志是一个布尔型变量的数组,如果线程1想访问临界区,就把下标为1的元素设为true,先检查标志再加锁。如违反忙则等待原则
  • 双标志后检查:先加锁后检查。违反空闲让进、有限等待。
  • Pterson算法:在双标志后检查加法中遇到都想进入线程。违反让权等待原则。

互斥访问指令:

  • 中断屏蔽方法:使用开/关中断指令,适用于单处理机和内核进程。
  • TestAndSet:使用TS/TSL指令。
  • Swap:XCHG指令。

信号量

信号量是指系统中某种资源的数量,比如打印机。系统通过一对原语对信号量进行操作wait(S)和signal(S),可以简写为P(S)、V(S),即P、V操作

  • 整数型信号量:使用wait原语检查信号量是否大于0,大于0就让进程进入临界区,信号量减1,否则让进程等待下去直到信号不为0,相当于“进入区”。如果有进程退出临界区,就通过signal原语把资源加1。优点是实现了加锁和检查一起进行,缺点是这种信号量无法在没有空闲资源时让等待的线程阻塞,违反让权等待原则。
  • 记录型信号量:记录型信号量既记录资源数,还记录阻塞队列里的进程。进程需要进入临界区时,就使用wait原语,wait原语将信号量减1,如果信号量的剩余资源数小于0就把进程挂到信号量的阻塞队列里。如果一个进程使用完了资源,就通过signal原语退出,资源数加1,如果还是小于等于0,那么就唤醒等待队列里的进程,让它进入就绪状态。这样就不违背让权等待原则。

管程

信号量实现起来比较复杂,管程是一种能替代信号量功能的更简单的软件模块,结构如下:

  • 只在管程内共享的数据结构说明
  • 对数据结构进行操作的一组过程(函数)
  • 对数据结构进行初始化的语句
  • 管程的名字

管程的特点:

  • 进程只能通过管程提供的“入口”才能进入管程
    = 同一时间只有只有一个进程在管程内操作
### 操作系统中进程与线程的概念 #### 进程 (Process) 进程是操作系统结构的基础,表示程序的一次执行过程。每个进程都有独立的代码和数据空间(指令、栈、堆),具有分配资源的功能单位。进程由文本区(即代码)、数据区以及用户堆栈组成,并且拥有自己的地址空间[^1]。 ```c // 创建新进程的例子 pid_t pid; pid = fork(); // Unix/Linux创建子进程的方式 if (pid < 0){ printf("error in fork!"); } else if(pid == 0){ printf("I am child process"); } else { wait(NULL); // 父进程等待子进程结束 } ``` #### 线程 (Thread) 线程有时被称为轻量级进程(Lightweight Process),同一进程内的多个线程共享该进程中大部分的数据和状态信息,如文件描述符、信号处理设置等;但是它们各自有自己的调用栈(call stack) 和寄存器集合(registers set)[^2]。 ```java class MyThread extends Thread{ public void run(){ System.out.println("This is a thread."); } } public class Main { public static void main(String[] args) { new MyThread().start(); } } ``` ### 进程与线程的主要区别 - **定义不同** - 进程是一个具有一定独立功能的程序关于某个数据集上的一次运行活动,而线程则是进程的一个实体,是CPU调度和分派的基本单位[^3]。 - **开销方面** - 启动一个新的进程所需的时间较长,因为这涉及到加载新的环境并初始化所有的上下文。相比之下,启动一个新线程则要快得多,因为它只需要复制父线程的一些属性即可完成创建工作[^4]。 - **资源共享** - 不同进程之间无法直接访问对方的内存区域,如果需要交换数据,则必须通过特定机制实现跨进程通讯(IPC) 。然而,在同一个进程下的各个线程间可以直接读写彼此所在的全局变量或静态方法中的局部变量,因此更容易进行协作工作。 - **通信方式** - 对于多进程而言,通常采用消息队列(message queue), 套接字(socket pair) 或者管道(pipe)等方式来进行相互通信;而对于属于同一进程的不同线程来说,由于它们都处于相同的地址空间内,故可通过共享存储器(shared memory segment)来高效传递信息。 - **调度粒度** - 在现代操作系统里,实际被调度的对象往往是线程而非整个进程——尽管后者确实包含了前者所需的全部资源和支持条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值