操作系统(9) (并发-----原子性/互斥临界区/生产者消费者问题/临界区问题三条件/互斥性/进展性/公平性)

目录

1. 并发(Concurrency)的定义

2. 原子性(Atomicity)

3. 互斥(Mutual Exclusion)

4. 生产者-消费者问题(Producer-Consumer Problem)

5. 临界区Critical Section

6. 临界区问题(Critical Section Problem)及其解决方案三个条件:


\

1. 并发(Concurrency)的定义

  • 并发是指多个指令序列(multiple instruction sequences)同时执行(at the same time)。这可以通过多进程(multiple processes)或者多线程(multiple threads)来实现。
  • 这种情况通常出现在操作系统中,当有多个进程/线程运行时,它们可能会并行运行(parallel execution)或者并发执行(concurrent execution)。
  • 进程/线程(Processes/Threads)通过共享内存(shared memory)或消息传递(message passing)进行通信,也可以共享资源,如设备(devices)、变量(variables)和数据结构(data structures)等。

2. 原子性(Atomicity)

  • 原子性指的是一段操作必须是不可分割的,不能在中途被其他操作打断或看到其中间状态。这段代码要么完全执行,要么完全不执行,没有部分完成的状态
  • 举例:如果一个操作是原子的,那么即使多个进程或线程并发执行,这段代码也不会被其他进程或线程“看见”部分执行的结果。比如硬件提供的原子操作(如test_and_set)就是这样,即使在多核系统中,这种操作也是不可中断的。

3. 互斥(Mutual Exclusion)

  • 互斥是针对临界区的,它确保在同一时间只能有一个进程或线程进入临界区(critical section),其他进程或线程必须等待直到当前进程离开临界区。这可以防止多个线程或进程同时修改共享资源,从而避免数据不一致的问题。
  • 互斥通过某种同步机制来确保只有一个线程能进入临界区,比如使用锁(mutex),或者使用Peterson's solution这种软件实现。
  • 举例:在多线程程序中,若两个线程需要修改共享变量counter,互斥确保只有一个线程可以在某个时刻进入临界区并修改counter,另一个线程必须等待。

4. 生产者-消费者问题Producer-Consumer Problem

生产者和消费者共享一个有限大小的缓冲区,生产者负责往缓冲区中添加项,消费者则从缓冲区中取出项。这个问题的挑战在于如何保证生产者和消费者在不发生冲突的情况下操作同一个缓冲区。

主要概念:

  • 有界缓冲区(Bounded Buffer):缓冲区中最多可以存放 N 个项。
  • 计数器(Counter):用于记录当前缓冲区中存放的项的数量。
    • 当生产者添加项时,计数器增加。
    • 当消费者取出项时,计数器减少。

并发问题:

和其他并发计算一样,生产者和消费者可能会因为共享资源(缓冲区)和计数器而产生竞争条件(Race Condition)。这可能导致缓冲区溢出或消费者读取空缓冲区等问题。

代码说明:

生产者(Producer)逻辑:

while (true) {

    // 当缓冲区满时,生产者等待

    while (counter == BUFFER_SIZE) ; /* do nothing */

    // 有空间时,生产者添加新项

    buffer[in] = new_item;

    in = (in + 1) % BUFFER_SIZE;  // 环形缓冲区的实现

    counter++;  // 更新计数器

}

  1. 等待:如果缓冲区已满(counter == BUFFER_SIZE),生产者会等待。
  1. 添加项:当有空间时,生产者会把新的项添加到缓冲区中,并更新缓冲区索引 in,这个索引是一个环形缓冲区的实现,防止数组越界。
  2. 计数器递增:生产者成功添加项后,计数器 counter 自增。

消费者(Consumer)逻辑:

while (true) {

    // 当缓冲区为空时,消费者等待

    while (counter == 0) ; /* do nothing */

    // 从缓冲区中取出项

    consumed = buffer[out];

    out = (out + 1) % BUFFER_SIZE;  // 环形缓冲区的实现

    counter--;  // 更新计数器

    // 消费该项

}

  1. 等待:如果缓冲区为空(counter == 0),消费者会等待。
  2. 取出项:当有项可以消费时,消费者从缓冲区中取出项,并更新缓冲区索引 out。
  3. 计数器递减:消费者成功取出项后,计数器 counter 自减。

5. 临界区Critical Section

临界区定义:

  • 临界区(Critical Section)是进程中一段需要访问共享资源的代码,这段代码不能与其他进程同时执行。
  • 假设有 n 个进程 P0,P1,...,Pn−1P0, P1, ..., Pn-1P0,P1,...,Pn−1,每个进程都有一段代码被称为“临界区”。
  • 进程在临界区中会修改共享变量、更新表格、写入文件等。当一个进程在执行临界区代码时,其他进程不能进入它们的临界区。

临界区的典型流程如下:

  1. 进入临界区前,检查或同步机制。
  2. 在临界区内执行共享资源相关操作。
  3. 退出临界区,允许其他进程进入。

6. 临界区问题(Critical Section Problem)及其解决方案三个条件:

1. 互斥性Mutual Exclusion):

  • 共享厨房中的某些资源(如炉灶或冰箱)一次只能被一个学生使用。如果两个学生同时尝试使用同一个资源,可能会导致混乱、冲突,甚至事故。因此,必须确保同一时间只有一个人可以使用这些资源。
  • 这种情况类似于临界区中的互斥条件:当一个进程在访问共享资源时,其他进程必须被阻止,直到该进程完成操作。

2. 进展性Progress):

  • 如果厨房空闲且有学生想要使用厨房,那么那些已经准备好烹饪的学生应该能够进入厨房,开始使用资源。决定谁可以进入厨房应该基于学生的实际准备情况,而不是随机因素。
  • 这对应着进展条件:当没有进程在临界区内时,进程应该能够及时进入,而不应该被其他不相关的进程或因素阻挡。

3. 公平性/有界等待Fairness/Bounded Waiting):

  • 如果有学生正在等待使用炉灶,应该有一个限制,确保这个学生不会无限期等待,直到所有其他学生完成烹饪。这样可以确保每个学生都有公平的机会,不会因为过多的等待而导致无法使用资源。
  • 这与有界等待条件相似:每个进程在请求进入临界区后,应该有一个限制,确保它最终可以进入,而不会无限期等待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/59312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue进阶指南:Watch 和 Computed 的深度理解

前言 在 Vue.js 开发中,我们常常会用到 watch 和 computed。虽然它们都能用来监听和处理数据的变化,但在使用场景和性能上有显著的区别。本篇文章会通过通俗易懂的方式给你讲解 Vue.js 中 watch 和 computed 的区别和使用方法。 基本概念 Computed&am…

如何对数据库的表字段加密解密处理?

对于表格数据的加密处理,通常涉及到对数据库中存储的数据进行加密,以保护敏感信息。 Java示例(使用AES算法加密数据库表数据) 首先,你需要一个数据库连接,这里假设你使用的是JDBC连接MySQL数据库。以下是…

【AI+教育】一些记录@2024.11.04

一、尝新 今天尝试了使用九章随时问,起因是看到快刀青衣的AI产品好用榜,里面这么介绍九章随时问:「它不是像其他产品那样,直接给你出答案。而是跟你语音对话,你会感觉更像是有一位老师坐在你的旁边,一步步…

DNS域名解析实验

准备工作 [rootlocalhost ~]# setenforce 0 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# mount /dev/sr0 /mnt [rootlocalhost ~]# dnf install bind -y DNS正向解析: 对主配置文件进行修改 [rootlocalhost ~]# vim /etc/named.conf 正向解析…

vite如何自定义插件,vite如何优化,代码示例

自定义Vite插件 1. 创建插件函数 - Vite插件是一个包含 name 属性和 transform (或其他钩子函数)的对象。 name 是插件名称, transform 用于转换代码。 - 例如,创建一个简单的插件,将代码中的 console.log 替换为自定…

Java的断点调试

在Java中,可以使用断点调试来调试程序并查看变量的值、程序的执行流程等。下面是使用Eclipse IDE进行Java断点调试的步骤: 在代码中选择要设置断点的行,通常是希望在程序执行到该行时暂停。右击所选行,选择"Toggle Breakpoi…

Jmeter参数化的4种方法 你get了吗?

1. 用Jmeter中的函数获取参数值 __Random,__threadNum,__CSVRead,__StringFromFile,具体调用方法如下: KaTeX parse error: Expected group after _ at position 2: {_̲_Random(,,)},,KaTeX p…

CF D. Genokraken

原题链接:Problem - D - Codeforces 题意:交互题,每次可以询问二个点之间的简单路径是否通过0点,如果通过返回1,否则返回0,要求输出每个节点的父亲。对于这颗树有三个特殊条件。1,如果断开0节点…

C语言 运算符

时间:2024.11.4 一、学习内容 1、算数运算符(加、减、乘、除法和取余) 通用细节: 1.整数计算,结果一定是一个整数 2.小数计算,结果一定是一个小数 3.整数和小数计算,结果一定是一…

php反序列化靶场随笔分析

项目地址:github.com/mcc0624/php_ser_Class 推荐使用docker部署:https://hub.docker.com/r/mcc0624/ser/tags 前面讲了以下php基础,我们直接从class6开始实验 class6 访问页面,传一个序列化的字符串,php代码将其反…

nginx代理websocket服务

一、nginx代理websocket服务 一)nginx代理ws服务 在nginx中,可以通过proxy_pass指令来代理WebSocket服务。 以下是一个示例配置: map $http_upgrade $connection_upgrade {default upgrade; close; }upstream ws_backend {server 127.0.0.1:…

56合并区间 go解题

这里解法是直接找一个快排模板,然后排序了第一个数,所以需要多加一个判断逻辑并且稍微覆盖。 package mainimport "fmt"func main() {fmt.Println(merge([][]int{{0, 2}, {2, 3}, {4, 4}, {0, 1}, {5, 7}, {4, 5}, {0, 0}}))// fmt.Println(m…

贝叶斯+PINN!双重热点buff叠加,轻松斩获Nature子刊!

PINN一直以来都是顶会顶刊上的大热方向,相关研究量多且质量高。最近,有关“贝叶斯PINN”的研究取得了不少突破,多项成果被Neurips、Nature子刊等录用。 事实上,这个结合方向的研究热度正逐渐上升,因为其在提高泛化能力…

【rust】rust基础代码案例

文章目录 HelloWorld斐波那契数列计算表达式(加减乘除) HelloWorld fn main() {print!("Hello,Wolrd") }斐波那契数列 fn fib(n: u64) -> u64 {let mut a 0;let mut b 1;for _ in 0..n {let c a b;a b;b c;}a }fn main() {let n 1…

Python模拟真人动态生成鼠标滑动路径

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…

从网络到缓存:在Android中高效管理图片加载

文章目录 在Android应用中实现图片缓存和下载项目结构使用 代码解析关键功能解析1. 图片加载方法2. 下载图片3. 保存图片到缓存4. 文件名提取 或者通过学习glide 首先我们需要在配置AndroidManifest.xml里面添加 <uses-permission android:name"android.permission.IN…

react-router与react-router-dom的区别

写法上的区别&#xff1a; 写法1: import {Swtich, Route, Router, HashHistory, Link} from react-router-dom;写法2: import {Switch, Route, Router} from react-router; import {HashHistory, Link} from react-router-dom;react-router实现了路由的核心功能 react-router-…

如何在C下比较两个字符串是否相同?

strcmp函数 strcmp函数是C标准库中用于比较两个字符串的函数。它的原型定义在string.h头文件中 函数原型&#xff1a; int strcmp(const char *str1, const char *str2); str1 和 str2 是两个要比较的字符串。返回值为整数类型&#xff1a; 如果返回值为0&#xff0c;表示两…

为数据集而生的 SQL 控制台

随着数据集的使用量急剧增加&#xff0c;Hugging Face 社区已经变成了众多数据集默认存放的仓库。每月&#xff0c;海量数据集被上传到社区&#xff0c;这些数据集亟需有效的查询、过滤和发现。 Dataset Monthly Creations 每个月在 Hugging Face Hub 创建的数据集 我们现在非常…

modelscope下载Qwen2.5 72B 模型方法

conda create -n modelscope python=3.10 conda activate modelscopepip install modelscope执行这个python代码: from modelscope.hub.snapshot_download import snapshot_download# 下载模型到当前路径 model_dir = snapshot_download(