操作系统原理实验二(一)

写在开头

    近日新型冠状肺炎很严重,学校也开不了学了,在MOOC上学习操作系统原理时
    看到MOOC上推荐完成的实验题,在这里记录一下。 
    本篇给出 4.1,4.2两题的解析,3-7在下一篇中分享

4.1 (实验目的:熟悉Window进程创建过程)在Windows环境下,利用高级语言编程环境(限定为VS环境或VC环境)调用相关的系统调用(CreateProccess,即系统API)实现一个包括“进程创建,文件读写”的应用程序。有一个文本文件CommandList.txt,第一行是说明性文字:本文件最后一次打开和运行日期是20190407。第二行开始每行是一个可执行程序的名称(含路径)。编写一个应用程序能打开该文件,并顺序执行其中的每个程序,并更新文件第一行中的日期。

[下面有一个文本文件CommandList.txt的截图]


| 本文件最后一次打开和运行日期是20190407 |

| c:\Windows\system32\notepad.exe |

| c:\Windows\system32\calc.exe |

| c:\Windows\system32\mspaint.exe |

|-------------------------------------------------------------------|

4.2 (实验目的:熟悉Linux fork创建进程的方法)在Ubuntu或Fedora环境使用fork函数创建一对父子进程,分别输出各自的进程号和提示信息串。
----------------------------------------------------------------------------------------------------

4.1Window进程创建

运行效果

三个进程被打开
在这里插入图片描述
且文件第一行的日期更改了
在这里插入图片描述

代码展示

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<time.h>
#define LINE 1024//一行最大字符数


char nowtime[64];//存储获取的当前时间
void getCurrentTime()
{
	struct tm t;   //tm结构指针

	time_t now;  //声明time_t类型变量
	time(&now);      //获取系统日期和时间

	localtime_s(&t, &now);   //获取当地日期和时间

	strftime(nowtime, sizeof(nowtime), "%Y%m%d\0", &t);     //年月日 ->nowtime
}

//该函数用于将文件第一行改变
void changeData(FILE* fp)
{
	//采用:另创建一个备份文件,改变第一行,再把无关行复制过去,
	//然后删除原文件,讲备份文件改名为原文件名
	char tmpname[] = "tmp";//临时新文件名
	FILE* fpNew;
	//打开临时文件
	errno_t err;
	if ((err = fopen_s(&fpNew, tmpname, "w")) != 0)//w表示对文件可写
	{
		printf("文件打开失败!");
		exit(1);
	}

	char buf[LINE]= "本文件最后一次打开和运行日期是";
	getCurrentTime();//加载时间 将时间赋给nowtime[]
	strcat_s(buf,nowtime);//将时间连接到后面
	strcat_s(buf, "\n");//末尾加一个换行

	char* p;
	fputs(buf, fpNew);//将buf里的内容输入文件中

	fgets(buf, LINE, fp);//这里读取第一行只是为了指针指向下一行
	/*
		解释一下,fgets()第一次运行会把第一行读出来,第二次运行会读出第二行
		所以这里运行一次,是因为拷贝只从第二行开始
	*/
	//循环将原文件2-n行复制到临时文件
	while (1)
	{
		p = fgets(buf, LINE, fp);
		if (p == NULL)
			break;//判断是否读取完
		fputs(buf, fpNew);
	}

	fclose(fp);
	fclose(fpNew);
	remove("D:\\C语言相关\\我的代码\\操作系统原理\\创建进程\\CommandList.txt"); //删除原文件
	rename(tmpname, "D:\\C语言相关\\我的代码\\操作系统原理\\创建进程\\CommandList.txt"); //重命名新文件
}
int main()
{

	FILE* fp;
	errno_t err;
	if ((err = fopen_s(&fp, "D:\\C语言相关\\我的代码\\操作系统原理\\创建进程\\CommandList.txt", "r"))!=0)//r表示对文件可读
	{
		printf("文件打开失败!");
		return 0;
	}

	//修改第一行: 本文件最后一次打开和运行日期是~~~~
	changeData(fp);
	//因为fgets而每次读取一行且不能回头,只能再打开一遍文件,使得fgets读取的是第一行
	if ((err = fopen_s(&fp, "D:\\C语言相关\\我的代码\\操作系统原理\\创建进程\\CommandList.txt", "r")) != 0)//r表示对文件可读
	{
		printf("文件打开失败!");
		return 0;
	}
	char buf[LINE];
	char* p;
	//读取一下第一行跳过他
	p = fgets(buf, LINE, fp);

	while (1)
	{
		p = fgets(buf, LINE, fp);
		if (p == NULL)
			break;
		
		//这里讲一下,因为fgets,会把每句后面的换行符'\n'也读取,但是这样子是运行不了的,
		//得把'\n'删掉,用'\0'做结尾
		int length = strlen(buf);
		if (buf[length - 1] == '\n')
			buf[length - 1] = '\0';
		
		//进程的参数
		STARTUPINFO si = { sizeof(si) };
		PROCESS_INFORMATION pi;
		BOOL ret;
		si.dwFlags = STARTF_USESHOWWINDOW;//指定wShowWindow成员有效
		si.wShowWindow = TRUE;//是否显示创建出来的进程窗口

		//将char 转为  TCHAR,因为(下面是一位大神讲的)
		//lpCommandLine是LPTSTR而不是LPCTSTR,所以这个参数不能是字符串常量,
		//必须是可写的字符串数组
		//然后我看另一位大神的代码  发现他是用的 TCAHR 可行0.0嘿嘿
		//(我在下面会给出两个大神的链接)
		TCHAR command[LINE];
		MultiByteToWideChar(CP_ACP, 0, buf, -1, command, LINE);

		//创建一个进程,可以用它来执行一个程序
		ret = CreateProcess(NULL, command, NULL, NULL, FALSE, 
		CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
		if (ret == false)
			printf("进程创建失败");
	}
	
	return 0;
}

简单解释一下

先把两位大神的链接发一下:
各个参数的含义:Windows下创建进程-CreateProcess()
实例:VC++ 使用CreateProcess创建新进程

至于代码的话,我在上面又添加了很多注释,大家可以对照注释理解,如果有不明白,或者要指正的欢迎评论区留言。

4.2Linux fork创建进程

运行效果

在这里插入图片描述
输出了父进程和子进程的进程号

代码展示

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

void main()
{
	//先输出该进程的进程号
	fprintf(stdout,"I am the first process,my pid is %d,my parent pid is %d\n",getpid(),getppid());

	//创建进程
	pid_t pid;
	if((pid=fork())<0)
	{
		//如果进程创建失败
		fprintf(stderr,"fork failed!");
		exit(0);
	}
	else if(pid==0)//子进程fork()返回值为0
		fprintf(stdout,"I am the child process,my pid is %d,my parent pid is %d\n",getpid(),getppid());
	else//父进程fork()返回值为子进程进程号
		fprintf(stdout,"I am the parent process,my pid is %d,my child pid is %d,my parent pid is %d\n",getpid(),pid,getppid());
}

简单解释一下

每个进程都有一个进程id(大于0的整数),
getpid()可以返回进程id,getppid()返回父进程的pid。

fork() 会创建一个子进程,
在父进程中返回值为子进程的id,在子进程中返回值为0

参考资料:Linux环境下编程(一)——进程fork()的使用

写在结尾

希望以上可以帮到你!
如有错误,或不同想法,欢迎指出,互相学习共同进步!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值