操作系统综合实验1(二)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 操作系统综合实验1

图 23显示该程序第二次运行后并没有返回到 shell 提示符,如果此时用另一个终端执行 ps 命令可以看到该进程处于S+状态,如图 24所示。


f4d9ec682f784f1d8ff10737572f3eef.png


图 24 查看 psem-named-wait-demo 的运行状态


再接下来看 P 操作,使得前面的 psem-named-wait-demo 进程从原来的阻塞状态唤醒并执行结束。程序如图 25所示,这里也要注意实际上代码并没有对sem_open()的返回值进行判断。


d89995ded30a45cd9658e3d967d660f4.png


图 25 psem-named-post-demo.c 代码


编译并执行 psem-named-post-demo(与前面不在同一个终端 shell 上),可以看到此时信号量的值增加到 1,并使得原来阻塞的psem-named-wait-demo被唤醒并执行完毕,如图 26所示。


0c9594e39f6c47f5abef40826e89cf0f.png


图 26 psem-named-post-demo 的运行输出


同时可以看到,原来阻塞的 psem-named-wait-demo 被唤醒并执行完毕,如图 27所示。


7381de443f3b41f3be2d36e80c900775.png


图 27 唤醒阻塞的 psem-named-wait-demo 进程


最后,如果不希望使用这个信号量可以通过 sem_unlink()撤销该信号量,如图 28所示。


4899ffa256b64ccfb2d37a8adb87a633.png


图 28 psem-named-unlink-demo.c 代码


而 POSIX 无名信号量适用于线程间通信,如果无名信号量要用于进程间同步,信号量要放在共享内存中(只要该共享内存区存在,该信号灯就可用)。无名信号量使用sem_init()创建。


互斥量是信号量的一个退化版本,仅用于并发任务间的互斥访问。下面先用一个代码来展示多线程并发且没有用互斥量保护共享变量的情形,如代码4-10 所示,此时结果可能会出现错误。该程序对一个缓冲区(缓冲区内是数值为 3、4、3、4......交织的整数)内的每个整数进行检查,并对数值为 3 的整数进行计数统计,统计工作由16 个线程并发完成(每个线程负责缓冲区的 1/16 的数据)。


下面的代码 no-mutex-demo.c 展示多线程并发且没有使用互斥量保护共享变量的状况,代码如图 29所示,编译后运行 no-mutex-demo,所得结果如图 30所示。可以看到,每次运行的结果并不唯一,共享变量没有被互斥访问。


1987c697ef874b2bb74507ed5f1a860c.png


图 29 no-mutex-demo.c 代码


ff354ccfe9e942cba9298a8a5ccb1460.png


图 30 no-mutex-demo 的运行结果


如果对 count++这个临界区加以保护,即增加一个互斥量 mutex m;就能避免出现这个问题。编译运行no-mutex-demo1,每次运行都能获得相同的结果。代码如图 31所示,结果如所示。由于实现了共享变量的互斥访问,因此每次运行的结果都是确定的值。


cccb21e9140c413a946da25ceb21fbc8.png


图 31 no-mutex-demo1.c 代码


2c1ce225cd5f4e0b8cfcda6eae4e92a1.png


图 32 no-mutex-demo1.c 结果


      至此,自行完成的Linux学习与实践全部结束。


2 使用POSIX信号量完成生产者与消费者的同步关系


根据前面的学习与本地的题目要求,我们可以得到设计的思路:


(1)要创建一个生产者消费者共用的缓冲区;


(2)对于生产者程序,首先要获取共享内存区并且挂入内存,之后创建三个信号量,将读取的行写入缓冲区(信号量在过程中要有对应的操作),然后释放信号量,结束内存映射并删除共享内存区域;


(3)对于消费者程序,同样要获取共享内存区并挂入内存,之后获取三个信号量,将缓冲区中的行字符串打印(信号量在过程中要有对应的操作),然后释放信号量。这里需要创建两个进程并发的进行上述操作。


头文件:


首先,定义如图 33的头文件,定义NUM_LINE=16作为共享内存的行数(可存储的行数),每行的内存大小为256;并且定义三个信号量分别用来判断是否互斥以及共享内存的空、满。


12df8a5139054dc7ba4dc7828918962b.png


图 33 头文件


生产者代码:


      由于本次实验已经给出了代码框架,只需要补充框架中对应的内容即可。补全代码如图 34,定义共享内存指针、共享内存id以及访问共享内存的信号量指针,然后获取共享内存区,并将共享内存映射到内存空间。


04ead60c92a749ee85c330404c837b5d.png


图 34 获取共享内存区并放入内存


之后需要创建三个信号量,sem_queue、sem_queue_empty、sem_queue_full 的信号量初始值分别为 1、NUM_LINE 和 0,具体如图 35:


edd515c839f140719ac5f5033164e175.png


图 35 创建信号量


接下来如图 36,将读写指针初始化,开始时都指向第0行,将输入的行写入缓冲区,并且要有信号量操作。对共享区域加锁,输出信号量的值,把输入的内容存入共享区域,更新写操作的行并判断:如果是quit 则跳出循环。


1d4a546a36cd4a33abb721cc888f5a12.png


图 36 将输入的行写入缓冲区


最后一部分如图 37,为释放信号量,结束共享内存在本进程的挂载映象,删除共享内存区域。该部分仿照前面的实验指导部分完成。


a42158f9b3bb4a019592d4fbfeac0091.png


图 37 释放信号量


生产者代码:


如图 38,消费者代码与生产者代码相似,首先获得生产者代码中的已创建的共享内存,然后将共享内存区映射到本进程的进程空间。


929c832a0d2c4c7cae796315e0b816f5.png


图 38 生产者获取共享内存区


      如图 39,然后要获取 生产者创建的 3 个信号量。创建两个进程,当进入子进程时先等待信号量,进行 P 操作,当成功后打印消费内容及进程号,发现 quit 后退出,释放信号量。父子进程都采用相同的处理方式。


831a23e53ba94c6ba85c9ee7b808c934.png


图 39 生产者信号量操作


      如图 40,同图 39,父子进程采用相同的处理方式。此处要注意的是,父进程释放信号量时,最后要加上 waitpid(fork_result,NULL,0); 用以等待所有的子进程结束后再退出,防止有孤儿进程生成。


2717133eff6c4652b10981a2f80e1479.png


图 40 生产者父进程信号量操作


      完成代码的编写后,将进行测试。如图 41,左侧为producer的运行,右侧为customer的运行,可以看到,程序完成了同步与通信功能,producer的输入通过共享内存,customer能够进行读取,producer输入的产品内容与customer输出的消费信息一一对应,其中产品号为奇数的内容对应父进程的运行,产品号为偶数的内容对应子进程的运行。当producer输入 quit 之后,两边都正常退出。


e615c445184c4b699f27b441a71e5dca.png


图 41 生产者/消费者问题的代码运行结果


3 设计简单Shell程序


根据前面的学习,我们可以知道,首先需要将输入的命令进行读入,并进行内部命令与外部命令的解析,如果成功解析出对应的命令则进行执行,否则视为无效命令。


首先,如图 42,引入必须的头文件,借助宏定义完成几个命令的分类并预先定义好几个函数。具体作用将在下面介绍。


6bfd9447cb6f45069507428f69c9aab3.png


图 42 shell程序的头文件以及函数


然后,定义如图 43的主函数。主函数的主要作用为申请存命令的空间,循环读入命令,并根据命令的不同做出对应的执行。在此,如“help”,“exit”等的内部命令将使用字符串比较的形式进行解析,并直接进行执行。


129a5eed307e4f2fb0e406eb46284b80.png


图 43 shell程序的主函数


由于shell需要打印提示符信息,在图 44中,我定义了一个函数获取当前目录并输出提示符。


ba1079890b854d1bbfe75d156921570d.png


图 44 shell程序的提示信息


对于帮助信息,将调用图 45中的函数直接输出帮助信息即可。


7c94bbae198d4c8baf3689ab8659b159.png


图 45 shell程序的帮助信息函数


由于要完成命令行的输入,我定义了如图 46的输入函数。利用循环将字符一个一个读入,当读入换行符或者超过长度时则终止循环。每次读入的时候都将读到的字符存入命令数组中。


50f6dadbcfc548648935cfb5e1484652.png


图 46 shell程序的读入函数


由于需要对命令进行解析,我定义了如图 47的函数。他将利用空格,对输入的命令进行拆分,分别存入数组中,直到遇到了换行符。


937e4838093b427fb21e54c10657f4f8.png


图 47 shell程序的命令解析函数


Shell中最重要的是执行命令。执行命令中最重要的是判断命令是否合法。并根据命令的类型(重定向命令,管道命令等)对命令进行分类,代码如图 48,首先需要将命令取出,并判断是否含有后台运行符。


9d87e76083ac4903b2ebe7874e9fbb41.png


图 48 shell程序的命令判断


接着,判断是否为重定向或者管道命令。如果非法则flag++,如果合法将进行分类。首先,对重定向符号以及管道符号进行判断,具体如图 49。在此将判断对重定向符号以及管道符号的个数,并对命令进行分类。然后对于重定向命令,将取出重定向命令的目标,并存入file变量中。如果是管道命令,则将管道符号后的可执行shell命令取出,以便进行执行。


02dbb34cdf284e06be8f7f892b43eb68.png


图 49 shell程序的重定向与管道命令的判断


完成了命令的分类,将进行命令的执行。首先,如图 50,如果不含有重定向及管道符号的最常规命令,直接调用execvp函数进行执行即可。


6bd2b9c048e64180a18035c9436d4c41.png


图 50 shell程序的常规命令执行


对于有输出重定向符号的命令,如图 51,利用dup2函数进行重定向即可。


cc91819f72504fafbc34981ba3679cca.png


图 51 shell 程序的输出重定向命令执行


对于有输入重定向符号的命令,如图 52,利用dup2函数进行重定向即可,与输出重定向类似。


bb68e0fe73114ead9c3a5e603f44e4d7.png


图 52 shell程序的输入重定向命令执行


对于管道命令,则相对复杂,需要利用子进程将管道符前面的命令执行完毕后再调用父进程完成管道符右侧命令的执行。具体代码如图 53,首先,使用fork开辟子进程,并利用子进程将管道符左边的命令的输出写入到借助中间文件里。这个过程中父进程需要等待子进程完成执行后再行执行。接着,父进程将由子进程写入的中间文件作为输入,运行管道符右侧的命令。最后删除暂存的文件即可。


7350483d78a946359770a5b933fa1ae3.png


图 53 shell程序的管道命令执行


此外,如果有后台运行符,则父进程直接返回而不需等待子进程。此时代码如图 54


6398226436734887ad74fc70bcf8199b.png


图 54 shell程序的后台运行符处理


此外,在每次执行的过程中都需要对命令进行查找,因此使用了如图 55的函数对命令进行查找。将分别在当前目录,bin目录,以及user下的bin目录进行查找。


4543c0ca8f604bc6848d4734e17a9eb6.png


图 55 shell程序的命令查找


所有代码如上,接下来进行测试如下。首先,测试内部命令“help”,效果如图 56,将打印帮助信息


b39b5a37d3004e78975e1e04794ba71b.png


图 56 shell程序输出帮助信息


      如果输入非法命令,则也会进行提示,具体如图 57


559c001f3d094b4c8cecf5ce3abebd63.png


图 57 shell程序非法命令


对外部命令的支持,首先,对“ls”进行测试,结果如图 58


4a6e0a7735e94de28d842a976c47aca6.png


图 58 shell程序ls运行结果


接着,对“ps”进行测试,结果如图 59


05ede1572e014edb8e6e699f23e1198b.png


图 59 shell程序ps运行结果


接着,对“cp”命令进行测试,在此,我测试使用cp命令复制“helloworld.c”文件,结果如图 60和图 61


988bf06da8b14a72aecb9472678b3227.png


图 60 shell 程序的cp命令


09886e74a33c4609ab855dade1175abc.png


图 61 shell 程序的cp命令结果


此外,还可以在我的shell里对c程序进行编译并运行,结果如图 62


de79377c79d04d9899c315e78fef46c7.png


图 62 shell程序对c代码的编译与运行


接着,测试管道功能,使用 ls | grep helloworld 和 ls | grep shell 作为指令。grep 指令是用于查找文件里符合条件的字符串,ls | grep helloworld 就是找出当下文件夹里含有helloworld的文件名并打印出来。在 myshell 下的运行结果如图 63所示,可以看到管道命令可以正常执行。


d701dd72046a4936910e91f75f63419e.png


图 63 shell程序的管道命令测试


接着,测试重定向功能。首先,对输入重定向进行测试。为了完成输入重定向的测试,我编写了一个简单的a+b程序,代码如图 64,并创建了用于重定向的文件,如图 65所示。


76f456e9252f4b4d9e8c48cc611945f2.png


图 64 a+b程序


e946da732ec64ca586977b10d1834790.png


图 65 输入重定向的文件


接着,在我的shell中,进行输入重定向的测试,结果如图 66,可以看到程序执行正确


f989cab68b2f425aa6352fa0a99b1052.png


图 66 shell的输入重定向测试


最后,对输出重定向进行测试,如图 67,使用ps命令,将结果重定向到“log.txt”中,结果如图 68。


79cac151ab1a4b38b4534e0ebad90869.png


图 67 shell的输出重定向测试


d527627d02484e76974f906e0545c356.png


图 68 shell输出重定向测试的结果


可以看到输出重定向的结果也符合预期。至此,shell编写完毕,我的shell可以接受内部,外部命令并以包含路径的信息作为提示符,可以在shell内部循环读取执行命令。此外,我的shell也实现了输入输出的重定向以及管道命令。


相关文章
|
2月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品体验与功能反馈摘要** 运维人员发现OS Copilot易上手,文档清晰,助其高效排查故障(8/10分)。愿意推荐并参与开源开发。亮点在于知识问答,能快速筛选答案。相较于竞品,优点是新手友好、文档清晰,但功能扩展性待增强。期望增加系统错误排查与解决方案,并集成ECS等,以优化系统安装流程。
阿里云操作系统智能助手OS Copilot实验测评报告
|
2月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
OS Copilot是针对Linux的智能助手,助力学习、运维及编程。用户界面直观,自然语言交互方便新手。官方文档详尽,但初次配置略复杂,适合学生和开发者。在提高代码编写和调试效率、系统学习上得分高,功能亮点包括代码生成、问答和命令执行。用户期待更多操作系统支持、自动错误分析和系统排查功能。
176 3
|
2月前
|
弹性计算 人工智能 运维
阿里云操作系统智能助手OS Copilot实验测评报告
阿里云操作系统智能助手OS Copilot实验测评报告
97 2
|
2月前
|
弹性计算 运维 监控
阿里云操作系统智能助手OS Copilot实验测评报告
阿里云OS Copilot助力学生提升学习效率,简化Linux操作。作为学生,体验者发现它在代码理解和诊断上极具价值,给予新手友好体验,但存在命令执行限制和错误处理问题。评分10/10,愿推荐并参与未来开发。功能上,知识问答、辅助编程和命令执行深受喜爱。对比其他产品,OS Copilot简洁集成,但需改善多命令支持和错误分析。期望支持更多操作系统及与ACK等工具联动,增强系统管理和故障排查。
40 1
|
2月前
|
弹性计算 运维 Linux
阿里云操作系统智能助手OS Copilot实验测评报告
体验OS Copilot对于新人使用是友好的,教程给出的比较全面,还支持语言问答,命令执行等优点,还允许用户直接在操作系统内部使用阿里云,完成ECS的实例查询等操作。但是在系统兼容上表现出不足,对于服务器地区不明确。但总体来说测评者对OS Copilot其智能化、高效化、专业化评价是高的。
45 1
|
2月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot的实验测评报告
OS Copilot 产品体验摘要 用户角色与场景:一位计算机学生使用辅助学习和解决问题,特别是通过代码解释功能加深理解。 易用性与文档:初者可能会觉得有些细节不明确。 帮助程度:用户给予极高评价,对学习帮助大,评分10分,快速定位和解决代码问题,提升学习效率。 推荐与参与:用户愿意推荐给他人。 功能体验:用户尝试了所有功能,对知识问答、辅助编程和命令执行特别感兴趣,尤其是命令执行帮助大。 对比其他产品:OS Copilot优点是便捷、准确。 期望功能:用户希望增加自动报错分析和系统错误排查。 联动体验:用户期待,以实现更全面的工具集。 总结:整体体验积极,用户看好其潜力,期待改进和未来联动。
|
2月前
|
弹性计算 运维 Python
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品测评摘要** - 学生使用,用于学习和编码,发现上手难度较高,指引文档不清晰,特别是Access ID设置和代码复制流程。 - 功能上,评分9分,辅助编程和知识问答功能显著提升了学习效率,减少了错误。 - 愿意推荐,并有兴趣参与开源开发以提升自我。 - 希望增强错误排查,提供具体错误原因和位置。 - 联动ACK智能助手可增强学习效果。 [链接]: https://developer.aliyun.com/topic/instructions-for-os-copilot
|
2月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot的实验测评报告
阿里云OS Copilot是AI驱动的Linux操作系统助手,助于系统管理和运维。学生反馈它在代码解释和编写上有很大帮助,给予8-9分的评价。功能亮点包括自然语言问答、辅助编程和命令解释,简化操作,提升效率。尽管易用,但需基础Linux知识。用户期待更多功能如系统优化建议和代码优化。与ACK智能助手配合,实现故障排查和运维。适合寻求效率提升的个人和团队。
52 0
|
2月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
阿里云OS Copilot是面向Linux的智能助手,助运维工程师提升效率。易上手,文档清晰,对新人友好。提供自然语言问答、编程辅助,尤善理解与响应。评分10/10,推荐给同行。目前侧重辅助编程,期望支持更多OS、并发命令执行及错误分析。适合集成于ECS等,打造自动化工作流。期待开源版本与社区合作。
87 0
|
2月前
|
弹性计算 运维 安全
操作系统智能助手OS Copilot实验测评报告
**阿里云OS Copilot摘要** OS Copilot是面向开发者和学生的智能助手,尤其对学习编程和运维有显著帮助。虽然初期上手复杂,但其知识问答、辅助编程功能深受好评,评分10分。用户愿推荐给他人,并期待开源参与开发。产品优点包括多功能、便捷性和高准确度,但新手引导需改进。期望增加Windows支持和自动化错误分析功能。通过与ECS等产品联动,OS Copilot能提升整体效率,简化操作,展现云服务的未来潜力。
54 0