操作系统进程实验

操作系统进程实验


1. 实验内容说明

1.1 父子进程的协调合作

该程序运行后创建了一个子进程,父进程向子进程发送信号,并等待子进程完成。子进程创建一个新路径/text,而后睡眠,等待被kill信号唤醒,唤醒后先执行信号处理程序,在创建的新路径下新建一个文件并写入内容,然后子进程改换图像,运行ls程序打印出新路径下所有内容。

1.2 两进程的消息队列通信

服务端进程先运行,根据规定的关键字创建一块消息队列,等待客户端进程向消息队列写入信息,从消息队列读取客户端的消息,并向消息队列写入给客户端的回复信息。
客户端进程是一次性的,运行后,向消息队列写入信息,等待服务端进程读取,之后读取服务端进程的回复信息。

1.3 两进程的共享内存通信

该程序运行后,新建一块共享内存,并将之关联到进程的虚地址空间。父进程打开输入文件,每次从里面读入一行内容,写到共享内存区,共三次。子进程打开输出文件,每次从共享内存区读取内容后,将内容写入输出文件。父进程写入前子进程不能读,子进程没读取上次内容前,父进程不能写,父子进程的读写过程不能中断。使用三个信号量实现同步与互斥。

2. 实验内容程序框图

2.1 父子进程的协调合作

在这里插入图片描述

2.2 两进程的消息队列通信

在这里插入图片描述

2.3 两进程的共享内存通信

在这里插入图片描述

3. 实验数据结构及代码说明

3.1 父子进程的协调合作

父进程创建一个子进程后,父进程向子进程发送信号,并等待子进程完成。子进程创建一个新路径/text,而后睡眠,等待被kill信号唤醒,唤醒后先执行信号处理程序,在创建的新路径下新建一个文件并写入内容,然后子进程改换图像,运行ls程序打印出新路径下所有内容。

# include<sys/types.h>
# include<signal.h>
# include<unistd.h>
# include<stdio.h>
# include<wait.h>
# include<stdlib.h>
# include<sys/stat.h>

int main ( )
{
    int status=1; 
    pid_t pid;
    void func(); // 声明信号处理程序
    signal(SIGUSR1, func); //设置信号16的处理程序为func()
    while((pid=fork())==-1); 
    if(pid){//父进程
        printf("parent\n");
        kill(pid,SIGUSR1); //向子进程发送信号
        wait(&status); //等待子进程完成
        printf("Child %d,status=%d \n", pid, status); //打印子进程号和status  
    }
    else{//子进程
        printf("Before sleep\n");
        mkdir("./text", 0777);//在当前路径建立一个新目录text
        sleep(10);//进入睡眠,等待被kill信号唤醒
        printf("After sleep\n");
        //改换子进程图像,调用ls程序打印text目录下所有内容
        execl("/bin/ls", "ls", "-l", "./text", (char*)0);
        printf("excel error\n");//改换失败后显示提示
        exit(2);
    }
}

void func(){//信号处理函数
    FILE *f;//文件指针
    f = fopen("./text/message.txt", "w");//新建文件message
    fprintf(f, "%s", "I Love China!\n");//向文件写入内容
    fclose(f);//关闭文件
    printf("write finished!\n");//显示文件建立完成提示
}
3.2 两进程的消息队列通信
3.2.1 头文件

定义了消息队列关键字以及发送消息的数据结构

# include<errno.h>
# include<sys/types.h>
# include<sys/ipc.h>
# include<sys/msg.h>
# include<unistd.h>
# include<stdio.h>
# include<string.h>

# define MSGKEY 1949//消息队列关键字

struct msgtype{//发送消息的数据结构
    long mtype;//消息类型
    int text;//消息正文
};
3.2.2 Server主程序

根据规定的关键字创建一块消息队列,等待客户端进程向消息队列写入信息,客户端写入后,从消息队列读取客户端的消息,并向消息队列写入给客户端的回复信息。

# include"msgcom.h"

int main(){
    struct msgtype buf;
    int qid, pid=getpid();
    //创建消息队列
    if((qid=msgget(MSGKEY, IPC_CREAT|0666))==-1)
        return -1;
    while(1){
        msgrcv(qid, &buf, 512, 1, MSG_NOERROR);//等待接收
        printf("Server%d receive  : %d\n", pid, buf.text);

        buf.mtype = 2;
        buf.text = 1314;
        printf("Server%d send : %d\n", pid, buf.text);
        //构造回复消息并发送
        msgsnd(qid, &buf, sizeof(int), 0);
        }  
}
3.2.3 Client主程序

客户端进程是一次性的,运行后,向消息队列写入信息,等待服务端进程读取并回复,服务端回复写入后,读取服务端进程的回复信息。

# include"msgcom.h"

void main(){
    struct msgtype buf;
    int qid, pid=getpid();
    //获取消息队列描述字
    qid = msgget(MSGKEY, IPC_CREAT|0666);
    buf.mtype = 1;
    buf.text = 520;
    printf("Client%d send: %d\n", pid, buf.text);
    //构造消息并发送
    msgsnd(qid, &buf, sizeof(buf.text), 0);
    //等待回复消息并接收
    msgrcv(qid, &buf, 512, 2 ,MSG_NOERROR);
    printf("Client%d recevie : %d\n", pid, buf.text);
}
3.3 两进程的共享内存通信
3.3.1 头文件

主要定义了创建信号量函数和对信号量的操作semWait和semSignal函数。

# include<sys/types.h>
# include<sys/ipc.h>
# include<sys/sem.h>
# include<stdio.h>
# include<sys/shm.h>
# include<unistd.h>
# include<stdlib.h>

# define SHMKEY 2022 
# define SIZE 512
# define SEMKEY1 1997
# define SEMKEY2 1999
# define SEMKEY3 2001

static void semcall(int sid, int op){//对信号量的操作函数
    struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = op;
    sb.sem_flg = 0;
    if(semop(sid, &sb, 1)==-1){
        perror("semop");
		exit(-1);
    }
}

int creatsem(key_t key){//创建信号量函数
    int sid;
    union semun{
        int val;
        struct semid_ds *buf;
        ushort *array;
    }arg;
    if((sid=semget(key, 1 ,0666|IPC_CREAT))==-1){
        perror("semget");
		exit(-1);
    }
    arg.val=1;//将信号量初始值设为1
    if(semctl(sid,0,SETVAL,arg)==-1){
        perror("semctl");
		exit(-1);
    }   
    return(sid);   
}

void semWait(int sid){//对信号量-1
    semcall(sid, -1);
}

void semSignal(int sid){//对信号量+1
    semcall(sid ,1);
}
3.3.2 主程序

父进程每次从输入文件读出内容向共享内存区写入,子进程从共享内存去读出内容,写入到输出文件中,共执行三个循环。此过程中父子进程一动一停,同步和互斥由三个信号量实现。
sid1是当前缓冲区能读次数,初始值为0
sid2是当前缓冲区能写次数,初始值为1
mutex是互斥信号量,初始值为1

# include"sem.h"

int main(){
    char *segaddr; //共享内存指针
    //sid1是当前缓冲区容量,mutex是互斥信号量
    int segid, sid1, sid2, mutex;
    //申请一块共享内存
    if((segid=shmget(SHMKEY, SIZE, IPC_CREAT|0666))==-1){
        perror("shmget");
		exit(-1);
    }  
    segaddr=shmat(segid, 0 ,0);//将共享内存关联到虚地址空间
    sid1=creatsem(SEMKEY1);//sid1是当前缓冲区能读次数
    sid2=creatsem(SEMKEY2);//sid2是当前缓冲区能写次数,初始值为1
    mutex=creatsem(SEMKEY3);//mutex是互斥信号量,初始值为1
    semWait(sid1);//将sid1的初始值置为0

    int i=0,j=0;//循环变量
    
    if(!fork()){//子进程sid1=0,sid2=mutex=1
        FILE *fp2 = fopen("./text/recever.txt","w");//打开输出文件
        while(j++<3){
        printf("son%d\n", j);
        semWait(sid1);//sid1-1
        printf("son before mutex\n");
        semWait(mutex);//mutex-1
        printf("son before puts %s\n", segaddr);
        fputs(segaddr, fp2);//将共享区内容写入输出文件
        semSignal(mutex);//mutex+1
        semSignal(sid2);//sid2+1
        }
        fclose(fp2);

    }
    else{//父进程
        FILE *fp1 = fopen("./text/send.txt","r");//打开输入文件
        while(i++<3){//输入文件一共有三行内容,每次读入一行写到共享区,共三次
        printf("fa%d\n",i);
        semWait(sid2);//sid2-1
        printf("fa before mutex\n");
        semWait(mutex);//mutex-1
        fgets(segaddr, 100, fp1);//从输入文件读入一行内容存到共享区
        printf("fa after gets %s\n", segaddr);
        semSignal(mutex);//mutex+1
        semSignal(sid1);//sid1+1
        }     
        fclose(fp1);
    }
}

4.实验结果

4.1 父子进程的协调合作

从执行结果的输出可以看出,父进程先获得了处理机,然后开始等待子进程的完成,子进程获得了处理机新建了./text目录,打印了before sleep。然后进入睡眠,然后没过多久(比10秒短很多)子进程就被kill信号唤醒,等到它获得处理机,它先执行信号处理程序,新建了message.txt文件,并打印了write finished,之后子进程改换图像,执行ls程序打印了text目录下的所有内容,也就是刚刚新建的message.txt。
在这里插入图片描述

打开message.txt文件发现内容与预期相符,说明信号处理函数工作正常。
在这里插入图片描述

4.2 两进程的消息队列通信

先运行服务端进程,服务端无反应,之后运行一个客户端进程,客户端收到了消息520打印后,回复了消息1314。客户端也接收到了消息1314并打印。之后客户端进程结束,服务端继续存活等待,之后再运行几个客户端进程,发现消息队列的收发情况合理运行,符合预期。
在这里插入图片描述

4.3 两进程的共享内存通信

子进程先获得了处理机,由于sid1为负而阻塞,父进程获得处理机,从输入问价读入了 I Love China!并将其写入共享内存区,之后第二次想写入的时候,sid2为负,被阻塞。子进程获得了处理机,从共享区读取了内容 I Love China!并将其写入了输出文件,之后第二次想读取的时候,sid1为负被阻塞。父进程获得处理机,继续写入…
可以看到,由于三个信号量的存在,使得父子进程间的读取和写入变得非常有序,不会发生冲突。
在这里插入图片描述

最终,打开输入输出文件想比对,结果符合预期。
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.基本系统进程   Csrss.exe:这是子系统服务器进程,负责控制Windows创建或删除线程以及16位的虚拟DOS环境。   System Idle Process:这个进程是作为单线程运行在每个处理器上,并在系统不处理其它线程的时候分派处理器的时间。   Smss.exe:这是一个会话管理子系统,负责启动用户会话。   Services.exe:系统服务的管理工具。   Lsass.exe:本地的安全授权服务。   Explorer.exe:资源管理器。   Spoolsv.exe:管理缓冲区中的打印和传真作业。   Svchost.exe:这个进程要着重说明一下,有不少朋友都有这种错觉:若是在“任务管理器”中看到多个Svchost.exe在运行,就觉得是有病毒了。其实并不一定,系统启动的时候,Svchost.exe将检查注册表中的位置来创建需要加载的服务列表,如果多个Svchost.exe同时运行,则表明当前有多组服务处于活动状态;多个DLL文件正在调用它。   至于其它一些附加进程,大多为系统服务,是可以酌情结束运行的。由于其数量众多,我们在此也不便于一一列举。   在系统资源紧张的情况下,我们可以选择结束一些附加进程,以增加资源,起到优化系统的作用。在排除基本系统及附加进程后,新增的陌生进程就值得被大家怀疑了。 更多内容请看Windows操作系统安装、系统优化大全、系统安全设置专题,或进入讨论组讨论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值