实验一 命令解释程序
实验内容
利用C语言编写一个微型命令解释程序minishell.c,该程序可接收并解释以下命令:
(1) dir 列出当前目录
(2) cop file1 file2 拷贝文件
(3) era filename 删除文件
(4) disp string 显示字符串
(5) end 结束,退出
要求:
(1)检查命令的合法性,如果有错误,显示出错信息,等待重新输入;
(2)命令前后有空格示为合法命令。
实验预备内容
- gets() 读入字符串,直到回车结束,但是不包括回车
- strcspn(str1,str2) 返回str1开头连续不包含str2的字符串
- strncpy(str1,str2,n) 将str2字符串的前n个复制到str1中
- strcmp(str1,str2) 将str1和str2进行比较
- 返回值小于0,str1 < str2
- 等于零 str1 == str2
- 大于零 str1 > str2
- system(command) 执行command
示例程序
#define true 1
#define false 0
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char cmdl[80];
char *scwt[] = {
"exit","dir","time"};
static int cmdnum = 3; // 可用命令数
char cmd[80];
int j,n;
while(true){
printf("Please input command:");
gets(cmdl); // 取命令行输入
n = strcspn(cmdl," ");// 取命令部分
if(n > 0 || strlen(cmdl) > 0){
strncpy(cmd,cmdl,n);
// 构成字符串
cmd[n] = '\0';
for(j = 0;j < cmdnum;j++){
if(strcmp(cmdl,scwt[j]) == 0) break;
}
if(j == 0) exit(0);
if(j < cmdnum){
system(cmdl);
continue;
}
printf("Bad command!\n");
}
}
}
实验代码
暂时先不放出来
实验二 进程管理
实验内容
1、进程的创建
编写一段程序,使用系统调用fork()创建两个子进程。让父进程显示字符串‘Parent:’;两个子进程分别显示字符串‘Child1:’和‘Child2:’。多次运行此程序,观察屏幕显示的结果,并分析原因。
2、进程控制
修改已编写的程序,将输出多次重复的一句话,观察程序执行时在屏幕上显示的结果,并分析原因。
若在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观察屏幕显示的结果,并分析原因。
实验预备内容和示例程序
fork 的测试
fork的功能描述:
- fork()通过复制进程来创建一个新进程。子进程类似于当前进程的副本,但是:
- 子进程有自己唯一的进程ID,而且这个进程的PID与任何进程的ID都不相同
- 子进程的父进程ID等于父进程的进程ID
- 返回值:
- 如果成功,在父进程中返回子进程的PID,在子进程中返回0
- 失败了,在父进程中返回-1,没有创建子进程
crescent_p@CP:~/Program/Experiment2$ gcc -o fork1 forkTest1.c
crescent_p@CP:~/Program/Experiment2$ ./fork1
fork test
fork test
#include <stdio.h>
#include <unistd.h>
int main(){
fork();
printf("fork test\n");
return 0;
}
分析:为什么输出了两次?
- 程序运行开始就创建了一个进程
- 当进程执行fork之后,创建了一个子进程
- 子进程的代码是父进程代码的副本
- 子进程的代码执行进度和父进程创建子进程时代码执行进度一致
测试二:
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t pid;
pid = fork();
// 父进程
if(pid > 0){
printf("I am father\n");
}
if(pid == 0){
printf("I an son\n");
}
if(pid < 0){
printf("fork error\n");
}
printf("main over\n");
return 0;
}
分析为什么结果不一样:
- 为什么又会出现son又会出现father?
- 在父进程中,fork()返回子进程的PID,大于0,因此会执行第一个if
- 在子进程中,fork()返回子进程的PID,等于0,因此会执行第二个if
- 为什么两次执行这个可执行文件结果不一样?
- 进程的异步性,我们设父进程为p1,子进程为p2
- 第一个执行:
- p1执行完第一个if,就轮到p2上处理机运行
- 第二个执行:
- p1执行完,才轮到p2上处理机
测试三:
#include <stdio.h>
#include <unistd.h>
int main(){
printf("执行到fork函数之前其进程为 %d,其父进程为 %d\n",getpid(),getppid());
sleep(1);
fork();
printf("这个进程id为:%d,它的父进程为%d\n",getpid(),getppid());
return 0;
}
测试四:
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t p1,p2;
while((p1 = fork()) == -1);
// 子进程
if(p1 == 0) {
puts("b");
}
else {
puts("a");
}
return 0;
}
实验代码
暂时先不放出来
实验三进程间的通信
管道通信
实验预备内容和示例程序
测试 pipe():
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(){
pid_t pid;
int fd[2];
char buf[50],s[50];
// 创建了管道,半双工
pipe(fd);
while((pid = fork()) == -1);
// 子进程
if(pid == 0){
sprintf(buf,"Child is sending message!");
// fd[1] 写入管道
write(fd[1],buf,50);
// exit 在退出前,还会把文件缓冲区中的内容写回文件
// 退出进程,其实是变成了一个僵尸进程
exit(0);
}else{
// 进程一旦调用了wait,就立即阻塞自己
// 由wait自动分析是否当前进程的某个子进程已经退出
// 如果让它找到了这样一个已经变成僵尸的子进程
// wait就会收集这个子进程的信息,并把它彻底销毁后返回
// 如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
wait(0);
// fd[0] 读取管道,将管道中的内容读入到s中
read(fd[0],s,50);
printf("%s\n",s);