> 文章列表 > 山东大学软件学院操作系统实验1(关于环境)

山东大学软件学院操作系统实验1(关于环境)

山东大学软件学院操作系统实验1(关于环境)

目录

1.写在前面

2.关于环境

3.关于函数和操作

4.具体代码


1.写在前面

2023年山东大学操作系统实验,第一次实验肥肠简单,压缩以后代码仅仅几行罢了

实验要求只是:创建一个父进程,然后创建子进程并且控制它每隔三秒输出一次当前目录下的文件(其实就是每隔三秒,让子进程完成一次ls -l操作)

这次试验主要是熟悉以下具体的操作,包括G系列的环境配置,在Linux环境下运行代码,进程相关的一些函数

2.关于环境

(1)操作系统:Ubuntu22.04(受到沙袋某校园app维护组成员的pua,我直接把电脑的操作系统改成了Linux,所以8要问我怎么配虚拟机,不会啊qwq)

(2)代码运行环境:g++(gcc是c语言编译运行的环境,g++是cpp的) , 或者也可以为了省事,直接安装vscode,clion等

3.关于函数和操作

主要是还是对于一些函数的操作和解释

(1)先解释一下指令是怎么执行的

可执行文件名   参数1 参数2 参数3

 可以发现大多数命令都是这样进行调用的,例如我们最常用的ll,其实原本为ls -l

其中ls就是可执行文件,完整的文件名应该是/bin/ls

(2)关于main函数中常用的两个参数

int main(int args,char * argv[]){//函数体
}

 这两个参数是啥玩意呢?这就要说我们的执行参数了

假设我们执行的时候(这个可执行文件叫main),执行指令是这样的

./main  1 2 3

 这样在命令行窗口,我们就可以执行这个main文件(前提是存在这样一个可执行的文件,对于cpp文件我们最好编译一下,编译过程我们后面再说,而且不一定编译以后一定是cpp文件)

这样传入进来的时候,我们在函数体内读取args和argv,分别能独到的数值是

4   //这个代表我们有四个参数

参数一共是四个,是当前文件名+三个参数

["./main","1","2","3",null]

参数数组严格来说长度为5,真实长度为4,包括指令的全部

理论上来说,这个确实是没啥用,但是后面实验可能有更多要求,而且和后面的execve函数密切相关

(3)在g++的环境下如何编译文件并且执行(下个vscode就不麻烦了)

g++ 你要编译的文件 -o 编译后的文件名./你要运行的文件名

 (4)下面解释六个基本函数以及相关的内容(注意以下函数都是linux下有效的)

pid_t pid=fork();

 fork函数是用来创建子进程的,子进程会根据父进程的副本进程创建,并且代码的执行范围是创建子进程开始,并且,返回的pid数值,如果为0,则代表当前的进程为子进程,如果为>0,则代表这是个父进程,<0代表进程创建失败,用这种方式来判断并且决定什么进程执行什么代码

(另外注意这个pid仅仅是一个识别号,并不是真正的进程号!!!!)

exit();

 没啥好说的,立刻退出当前进程

kill(pid,notion);

 向指定进程发送某种指令

execve(filename,arg[],env[])
perror("如果上述没执行成功,就会触发这一句,并且继续往下执行")

execve函数值得大书特书,因为这是一个系统调用的api,作用是改变当前进程接下来的执行内容

通俗来讲就是:不再执行下面的代码,转而执行指定的内容

实际作用上:相当于利用代码去在终端里执行一条指令

filename:是你要执行的文件名字(一定要可执行文件)

arg[]是个char* 类型的数组,他的组成为 文件名+参数+NULL

env也是类似的数组,组成为环境变量+NULL

(这两个数组必须以NULL结尾)

先举个栗子: 比如我们函数执行到一半,想要列出全部的文件内容 怎么办

首先我们知道,指令应该为 ls -l ,ls为可执行文件, -l为参数,在环境变量无所谓的情况下,我们的执行可以这样写

char * arg[]={"ls","-l",NULL};
char * env[]={NULL};
execve("ls",arg,env);

 ok,有时候可以结合上面main函数中的隐藏函数来进行处理

./main ls -l

 那么里面就可以写成

execve(argv[1],&argv[1],NULL)

//下面是几个无关痛痒的函数

int status;
pid_t pid=wait(&status);

 wait函数其实是一个阻塞方法,在父进程中使用,等待子进程完成以后,会把结束状态压入status中,并且返回这个wait函数对应的进程号.

每一个wait函数都会对应一个子进程,其中返回值大于0代表子进程结束

其他的返回值有不同的含义,详见文档

另外还有一个衍生的函数

waitpid(pid, status,opions)

pid是指定等待某个进程完成任务,而不是像wait一样按照子进程的顺序(注意pid=-1的时候有个等待集合的概念,这个要注意)

status是结束状态,以何种状态结束

options是默认行为,比如没有终止就立刻返回,里面有一些内置的常量

getpid()
getppid()

 获取当前进程号,获取父进程号

sleep();

指定线程休眠多少秒

 

4.具体代码

#include <bits/stdc++.h>
using namespace std;
int main(int args,char * arg[]){for(int i=0;i<5;i++){pid_t pid=fork();if(pid==0){char * args[]={"/bin/ls","-l",NULL};  char * envp[]={NULL};execve("/bin/ls",args,envp);}else if(pid<0)cout<<"err!!!"<<endl;sleep(3);}return 0;
}

在vscode中点击运行即可,参数已经内置