操作系统综合实验

news2024/11/30 2:50:39

实验目的

  • 加深对进程概念理解,进一步认识进程并发执行
  • 掌握Linux系统的进程创建和终止操作
  • 掌握文件系统调用及文件标准子例程的编程方法
  • 掌握Linux下终端图形编程方法,能编写基于文本的图形界面
  • 掌握proc文件系统的使用

相关知识

Linux C编程中的头文件

头文件含义
stdio.h标准输出输入
stdlib.h标准库头文件
string.h字符串处理相关函数
unistd.h类UNIX系统的系统调用
fcntl.h定义了文件信息控制
sys/types.h基本系统数据类型,包括多个派生类型
sys/stat.h方便获取文件属性
sys/time.h时间、日期相关函数

进程的创建

格式:

#include<sys/types.h>
#include<unistd.h>
pid_t getpid(void); //返回调用进程id号
pid_t getppid(void); //返回调用进程的父进程id号
pid_t fork(void);

说明:进程调用fork创建一个子进程,pid_t表示有符号整形量,若调用成功,则在父进程中返回子进程的pid,在子进程中返回0,创建失败返回-1;

fork()产生当前进程的拷贝,该函数“调用一次,返回两次”,即在父进程中调用一次,在父进程和子进程中各返回一次。开始是一个控制流程,调用fork之后发生分叉,变成两个控制流程,这就是fork名称的由来。

进程终止

格式:

#include<stdlib.h>
void exit(int status);

说明:exit()自我终止当前进程,使其进入僵死状态,等待父进程进行善后处理,status是返回给父进程的一个整数。

文件系统调用

文件使用方式:打开文件→文件读/写→关闭文件

  1. 打开文件—open
int open(filename,int flags);
int open(filename,int flags,mode_t mode);
标志含义
O_RDONLY以只读的方式打开文件
O_WRONLY以只写方式打开文件
O_RDWR以读写方式打开文件
O_APPEND以追加的方式打开文件
O_CREATE如没有要打开的文件,创建该文件
O_EXEC若使用了O_CREATE而且文件以及存在,就会发生一个错误
O_NOBLOCK以非阻塞的方式打开一个文件
O_TRUNC若文件已经存在,则删除文件的内容

mode为八进制数表示文件权限,例如:0640表示-rw-r-----

打开文件示例:

open("test",O_RDONLY|O_CREATE,0640); //成功则返回一个文件描述符,否则返回-1

文件描述符是由无符号整数表示的句柄,进程使用它来标识打开的文件。

文件描述符与包括相关信息(如文件的打开模式、文件的位置类型、文件的初始类型等)的文件对象关联,这些信息被称作文件的上下文。

内核利用文件描述符(file descriptor)来访问文件,在形式上它是一个非负整数,代表一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。习惯上,标准输入(standard input)的文件描述符是0,标准输出(standard output)是1,标准错误(standard error)是2。POSIX定义了STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO来代替0、1、2,这三个符号常量位于头文件unistd.h中。

  1. 读文件—read
ssize_t read(int fd, void * buf, size_t count);

说明:从文件描述符fd所指文件中读取count字节的数据,放到缓冲区buf中。如果成功则返回读取的字节数,出错返回-1;若在调read之前已到达文件末尾,则这次read返回0。

  1. 写文件—write
ssize_t write (int fd, const void * buf, size_t count);

说明:将缓冲区buf中count个字节写入文件描述符fd所指文件中去。若调用成功返回实际写入的字节数;若发生fd有误或者磁盘已满等问题,返回值 < count;若没有写出任何数据,则返回值为0;调用不成功返回-1,并将错误代码存入errno中。

  1. 关闭文件—close
int close(int fd); //成功返回0,否则返回-1

关闭文件和打开文件是配对的,即打开的文件最好要显式的关闭。

C库函数

C文件操作用库函数实现,包含在stdio.h中,系统自动打开和关闭三个标准文件:

  • 标准输入-键盘(stdin)
  • 标准输出-显示器(stdout)
  • 标准出错输出-显示器(stderr)
  1. 文件打开—fopen
    函数原型:
FILE *fopen(const char *filename, const char *mode)

该函数使用给定的模式 mode 打开 filename 所指向的文件。其中mode值为以下:

文件使用方式含义
“r”打开一个用于读取的文件。该文件必须存在。
“w”创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
“a”追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。
“r+”打开一个用于更新的文件,可读取也可写入。该文件必须存在。
“w+”创建一个用于读写的空文件。
“a+”打开一个用于读取和追加的文件。

返回值:该函数返回一个 指向文件结构体的FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。

  1. 文件读/写
    函数原型:
size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );
size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );

fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。对参数的说明:

  • ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。
  • size:表示每个数据块的字节数。
  • count:表示要读写的数据块的块数。
  • fp:表示文件指针。

理论上,每次读写 size*count 个字节的数据。
返回值:返回成功读写的块数,也即 count。如果返回值小于 count:

  • 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
  • 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror()feof() 检测。
  1. 文件关闭—fclose
    函数原型:fclose(fp)
    作用:关闭fp指向的文件,使文件指针变量与文件“脱销”,释放文件结构体和文件指针。正常关闭返回0;出错时返回非0;

curses编程

proc文件系统

proc文件系统是Linux中的特殊文件系统,提供给用户一个可以了解内核内部工作过程的可读窗口,在运行时访问内核内部数据结构、改变内核设置的机制。

  • 保存系统当前工作的特殊数据,但并不存在于任何物理设备中;
  • 对其进行读写时,才根据系统中的相关信息即时生成;或映射到系统中的变量或数据结构;
  • proc被称为’伪文件系统,
  • 其挂接目录点固定为/proc;
  • man proc进行了详细说明。

/proc的文件可以用于访问有关内核的状态、计算机的属性、正在运行的进程的状态等信息。大部分/proc中的文件和目录提供系统物理环境最新的信息。

尽管/proc中的文件是虚拟的,但它们仍可以使用任何文件编辑器或像more, lesscat这样的程序来查看。当编辑程序试图打开一个虚拟文件时,这个文件就通过内核中的信息被凭空地(on the fly)创建了。

得到有用的系统/内核信息
proc文件系统可以被用于收集有用的关于系统和运行中的内核的信息。下面是一些重要的文件:

文件含义
/proc/cpuinfoCPU的信息(型号、家族、缓存大小等)
/proc/meminfo物理内存、交换空间等的信息
/proc/mounts已加载的文件系统的列表
/proc/devices可用设备的列表
/proc/filesystems被支持的文件系统
/proc/modules已加载的模块
/proc/version内核版本
/proc/cmdline系统启动时输入的内核命令行参数

文件/proc/cpuinfo包含一个系统的CPU信息,十分清楚地给出了这个系统的有用的硬件信息。
可以使用以下命令查看:

ls -l /proc/cpuinfo

实验内容

编写一个C程序,使用Linux下基于文本的终端图形编程库curses,分窗口实时监测(即周期性刷新显示)CPU、内存和网络的详细使用情况和它们的利用率。

#include <curses.h>
#include <time.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{
    pid_t pid1, pid2, pid3;
    unsigned int receive0, send0;
    initscr();
    refresh();
    WINDOW *wp1, *wp2, *wp3; /*定义分屏,并指定各个分屏位置*/

    wp3 = subwin(stdscr, LINES, COLS / 3, 0, 0);
    wp2 = subwin(stdscr, LINES, COLS / 3, 0, COLS / 3 + 1);
    wp1 = subwin(stdscr, LINES, COLS / 3, 0, COLS / 3 * 2 + 2);
    if (start_color() == OK)
    {
        box(wp3, ACS_VLINE, ACS_HLINE);
        box(wp2, ACS_VLINE, ACS_HLINE);
        box(wp1, ACS_VLINE, ACS_HLINE);
        touchwin(stdscr);

        init_pair(1, COLOR_BLUE, COLOR_WHITE); /*定义一组颜色*/
        wattron(wp1, COLOR_PAIR(1));           /*激活颜色到分屏*/
        init_pair(2, COLOR_RED, COLOR_WHITE);
        wattron(wp2, COLOR_PAIR(2));
        init_pair(3, COLOR_GREEN, COLOR_WHITE);
        wattron(wp3, COLOR_PAIR(3));

        int sum = 0, i;
        if (0 == (pid3 = fork())) /*进程3负责监控cpu使用情况和利用率*/
        {
            FILE *fp;
            char buf[256];
            char cpu[5];
            long user, nice, sys, idle;
            long all1, all2, idle1, idle2;
            float usage, usage1, usage2;
            while (1)
            {
                fp = fopen("/proc/stat", "r");
                if (fp == NULL)
                {
                    perror("fopen:");
                    exit(0);
                }

                wmove(wp3,3,1);
                wprintw(wp3,"--------CPU INFO--------");
                fgets(buf, sizeof(buf), fp);
                sscanf(buf, "%s %ld %ld %ld %ld", cpu, &user, &nice, &sys, &idle);
                wmove(wp3, LINES / 2 - 3, 1);
                wprintw(wp3, "current cpu:\n  -user time: %ld\n  -nice time: %ld\n  -system time: %ld\n  -idle time: %ld\n", user, nice, sys, idle); /*两次获取求平均值。*/

                all1 = (user + nice + sys + idle) / 100;
                idle1 = idle / 100;
                rewind(fp);
                sleep(1);
                memset(buf, 0, sizeof(buf));
                cpu[0] = '\0';
                user = nice = sys = idle = 0;
                fgets(buf, sizeof(buf), fp);
                sscanf(buf, "%s %ld %ld %ld %ld", cpu, &user, &nice, &sys, &idle);
                all2 = (user + nice + sys + idle) / 100;
                idle2 = idle / 100;
                usage1 = (float)(all1 - idle1) / all1 * 100;
                usage2 = (float)(all2 - idle2) / all2 * 100;
                usage = (usage1 + usage2) / 2;

                wmove(wp3, LINES / 2 + 2, 1);
                wprintw(wp3, "current cpu use : %.2f\%\n", usage);

                curs_set(0);
                box(wp3, ACS_VLINE, ACS_HLINE);
                fclose(fp);
                sleep(1);
                wrefresh(wp3);
            }
        }
        if (0 == (pid2 = fork())) /*进程2负责监控内存使用情况和利用率*/
        {
            FILE *fp1;
            char buf1[256];
            char name1[20];
            char name2[20];
            unsigned long MemT, MemF;
            float usage3, usage4;
            while (1)
            {
                fp1 = fopen("/proc/meminfo", "r");
                if (fp1 == NULL)
                {
                    perror("fopen:");
                    exit(0);
                }
                wmove(wp2,3,1);
                wprintw(wp2,"------MEMEORY INFO-------");
                fgets(buf1, sizeof(buf1), fp1);
                sscanf(buf1, "%s %lu %s", name1, &MemT, name2); /*第一行是总内存*/
                fgets(buf1, sizeof(buf1), fp1);
                sscanf(buf1, "%s %lu %s", name2, &MemF, name2); /*第二行是空闲内存*/
                wmove(wp2, LINES / 2, 1);
                wprintw(wp2, "current memF : %lu\n", MemF);
                wmove(wp2, LINES / 2 + 1, 1);
                wprintw(wp2, "current memT : %lu\n", MemT);
                usage3 = (float)MemF / 100;
                usage4 = (float)MemT / 100;
                usage3 = (double)(1 - (usage3 / usage4)) * 100;
                wmove(wp2, LINES / 2 + 2, 1);
                wprintw(wp2, "current Mem use : %.2f\%\n", usage3);

                curs_set(0);
                box(wp2, ACS_VLINE, ACS_HLINE);
                fclose(fp1);
                sleep(3);
                wrefresh(wp2); /*刷新屏幕,显示输出内容*/
            }
        }
        if (0 == (pid1 = fork())) /*进程1负责统计从监控开始工作后接受和发送数据包数,并计算平均负载*/
        {
            FILE *fp2; /*获取最初的网络状态,即发送和接受数据包数*/
            char buf2[256];
            char ch[20];
            unsigned int receive1, send1;
            float usage5;
            fp2 = fopen("/proc/net/dev", "r");
            if (fp2 == NULL)
            {
                perror("fopen:");
                exit(0);
            }
            fgets(buf2, sizeof(buf2), fp2);
            fgets(buf2, sizeof(buf2), fp2);
            fgets(buf2, sizeof(buf2), fp2);
            fgets(buf2, sizeof(buf2), fp2);
            sscanf(buf2, "%s %u %u", ch, &send0, &receive0);
            fclose(fp2);

            while (1)
            {
                fp2 = fopen("/proc/net/dev", "r");
                rewind(fp2); /*指针回到最初的位置*/
                memset(buf2, 0, sizeof(buf2));
                ch[0] = '\0';
                fgets(buf2, sizeof(buf2), fp2); /*fgets获取字符数足够大时,就会从文件中以行的方式读入,*/
                fgets(buf2, sizeof(buf2), fp2); /*由于所需数据在文件第四行,所以调用fgets四次*/
                fgets(buf2, sizeof(buf2), fp2);
                fgets(buf2, sizeof(buf2), fp2);
                wmove(wp1,3,1);
                wprintw(wp1,"------NETWORK INFO-------");
                sscanf(buf2, "%s %u %u", ch, &send1, &receive1);
                wmove(wp1, LINES / 2, 1);
                wprintw(wp1, "current send: %u\n", send1 - send0); /*计算参数变化量,并求均值,即为平均负载*/
                wmove(wp1, LINES / 2 + 1, 1);
                wprintw(wp1, "current receive: %u\n", receive1 - receive0);
                usage5 = (float)((send1 - send0) + (receive1 - receive0)) / 2;
                wmove(wp1, LINES / 2 + 2, 1);
                wprintw(wp1, "average net load: %.2f\n", usage5);
                box(wp1, ACS_VLINE, ACS_HLINE);
                fclose(fp2);
                sleep(4);
                wrefresh(wp1);
            }
        }

        waitpid(pid1, NULL, 0);
        waitpid(pid2, NULL, 0);
        waitpid(pid3, NULL, 0);

        wattroff(wp1, COLOR_PAIR(1));
        wattroff(wp2, COLOR_PAIR(2));
        wattroff(wp3, COLOR_PAIR(3));
        refresh();
        getch();
    }
    else
    {
        waddstr(stdscr, "Can not init color");
        refresh();
        getch();
    }
    getch();
    endwin();
    return 0;
}

实验结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pp49LGt2-1671105257792)(Images/实验:综合实验输出.png)]

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

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

相关文章

知识点整合

⭐面试 自我介绍&#xff08;优势岗位匹配度&#xff09; 为什么来我们公司&#xff08;对公司的了解&#xff09; 讲讲做的项目&#xff08;为什么这么做&#xff0c;思路和贡献&#xff09; 跨部门涉案的业务流程 我们跨部门涉案业务主要是本系统、配合物流系统和罚没系…

二战字节跳动成功上岸,准备了小半年,拿27k也算不上很高吧~

先说下我基本情况&#xff0c;本科不是计算机专业&#xff0c;现在是学通信&#xff0c;然后做图像处理&#xff0c;可能面试官看我不是科班出身没有问太多计算机相关的问题&#xff0c;因为第一次找工作&#xff0c;字节的游戏专场又是最早开始的&#xff0c;就投递了&#xf…

SpringMVC传值

实现步骤 先看后台代码如何获取前端传过来的数据&#xff0c;直接在方法的参数列表中添加RequestParam(xxx)&#xff0c;再在后面加上参数列表即可 不过这样的方式会出现一个问题&#xff1a;当前端页面没有提交相应的数据过来的时候&#xff0c;后台会出现异常&#xff0c;所…

Elasticsearch7.8.0版本进阶——数据读流程

目录一、数据读流程概述二、数据读流程步骤2.1、数据读流程图2.2、数据读流程步骤&#xff08;从主分片或者副本分片检索文档的步骤顺序&#xff09;2.3、数据读流程注意事项一、数据读流程概述 从主分片或者从其它任意副本分片检索文档。 二、数据读流程步骤 2.1、数据读流…

5_机试_递归和分治

一、递归 本章介绍程序设计中的另一个非常重要的思想一递归策略。递归是指函数直接或间接调用自身的一种方法&#xff0c;它通常可把一个复杂的大型问题层层转化为与原问题相似但规模较小的问题来求解。递归策略只需少量的程序就可描述解题过程所需的多次重复计算&#xff0c;…

谈谈Java多线程离不开的AQS

如果你想深入研究Java并发的话&#xff0c;那么AQS一定是绕不开的一块知识点&#xff0c;Java并发包很多的同步工具类底层都是基于AQS来实现的&#xff0c;比如我们工作中经常用的Lock工具ReentrantLock、栅栏CountDownLatch、信号量Semaphore等&#xff0c;而且关于AQS的知识点…

DDR4 信号说明

SDRAM Differential Clock :Differential clocks signal pairs , pair perrank . The crossing of the positive edgeand the negative edge of theircomplement are used to sample thecommand and control signals on theSDRAMSDRAM差分时钟&#xff1a;差分时钟信号对&#…

MagicThoughts|让ChatGPT变得更智能的Finetuned数据集

近两个月&#xff0c;ChatGPT无疑都是AI领域最炙手可热的话题。而它的成功&#xff0c;也引发了行业内外对于对话式AI、LLM模型商业化应用可能性的思考。诚然&#xff0c;尽管就目前来看ChatGPT对大部分问答都能基本做到“对答如流”。但是&#xff0c;ChatGPT本质上依旧是预训…

Flutter Modul集成到IOS项目

Flutter Modul集成到IOS项目中1. 创建一个Flutter Modul2.在既有应用中集成Flutter Modul2.1 Flutter的构建模式选择2.1.1 debug模式2.1.2 Release模式2.1.3 Podfile 模式2.2 Cocoapods管理依赖库集成方式2.3 直接在Xcode中集成framework2.4 Local Network Privacy Permissions…

采用 spring 配置文件管理Bean

文章目录采用 spring 配置文件管理Bean一、安装配置Maven二、Spring 框架1、Spring 官网三、Spring 容器演示-采用Spring配置文件管理Bean1、创建Manev项目2、添加Spring依赖3、创建杀龙骑士类4、创建勇敢骑士类5、采用传统方式让勇敢骑士完成杀龙任务6、采用Spring 容器让勇敢…

创建Ubuntu虚拟机与Windows共享的文件夹

目录 1、Windows创建一个共享文件夹 2、在虚拟机的设置中选择Windows下的共享文件夹 3、在Ubuntu中查看共享文件夹 1、Windows创建一个共享文件夹 该共享文件夹可以被Windows和Ubuntu访问&#xff0c;需要注意的是&#xff0c;Ubuntu在共享目录下的一些操作会受到限制&…

图解经典电路之OCL差分功放-三极管分立器件电路分析

下面从简到繁,从框架到细节的顺序讲解电路。即先讲框架,然后逐渐添加电路细节,所以大家跟上思路。 1、第一步,尽可能的抽象这个电路,等效如下: 图二 OCL等效电路 整个OCL电路,可以等效为一个大功率的运放,加上几个电阻电容构成了一个同向放大器,就是这么简单。 为了便…

Linux常用命令---系统常用命令

Linux系统常用命令场景一&#xff1a; 查看当前系统内核版本相关信息场景二&#xff1a; sosreport 命令场景三&#xff1a; 如何定位并确定命令&#xff1f;场景四&#xff1a;查看当前系统运行负载怎场景五&#xff1a; 查看当前系统的内存可用情况场景六&#xff1a;查看网卡…

【DOTA】目标检测数据集介绍与使用

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 DOTA 数据集简单介绍 1. 正文 1.1 简介 数据集包含来自不同的传感器和平台的航拍图。每张图像的像素尺寸在 800 800 到 20,000 20,000 之间&#xf…

如何编写接口测试用例?

接口测试用例如何编写&#xff1f;下面简单给大家讲解一下。 接口测试用例是目前软件开发中不可或缺的一个重要部分&#xff0c;因此编写接口测试用例同样重要。 接口测试用例的作用非常明显&#xff0c;它能够帮助我们了解产品正在考验、调整它如何表现在特定情境之下、产品是…

2023金三银四,测试人还能找到好工作吗?

按照往年的惯例&#xff0c;春节后复工的 3 月、4 月是人员跳槽最频繁的时候&#xff0c;俗称“金三银四”。然而&#xff0c;市场大环境的影响&#xff0c;很多行业感受到了一丝寒冷的气息。我们以为受影响比较轻的互联网行业&#xff0c;头上也充满乌云&#xff0c;所谓互联网…

2023年浙江交安安全员考试题库及答案

百分百题库提供交安安全员考试试题、交安安全员考试真题、交安安全员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 50.根据《建设工程安全生产管理条例》第65条规定&#xff0c;施工单位有下列&#xff08;&#xff09;行…

JavaScript高级程序设计读书分享之3章——3.5操作符

JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 目录 操作符 一元操作符 递增/递减操作符 一元加和减 布尔操作符 逻辑非 逻辑与 逻辑或 乘性操作符 乘法操作符 除法操作符 取模操作符 加性操作符 加法操作符 减法操作符 关系操作符 相等操…

使用python将EXCEL表格中数据转存到数据库

使用Python将excel表格中数据转存到数据库 1. 思路&#xff1a; 1&#xff09; 使用python读取excel表格中数据 2&#xff09;根据数据生成sql语句 3&#xff09;批量运行sql语句 2. 代码&#xff1a; import pandas as pddef readExcel(path, excel_file):return pd.read_e…

低代码开发平台|制造管理-质检管理搭建指南

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建制造管理-质检管理。1.2、应用场景质检分别包括来料质检、过程质检、成品质检&#xff0c;来料质检在采购物料入库后会自动发起来料质检的流程&#xff0c;质检合格才可提交结束流程&#xff1b;过程检是在生产过程中的质检…