操作系统进程管理
项目
1.软中断
内容1:系统调用是一种进入系统空间的办法。linux的系统调用是通过中断机制实现的。中断这个概念涉及计算机系统结构方面的知识,显然它与微处理器等硬件有着密不可分的关系。软中断,是对硬中断的一种模拟,发送软中断就是向接收进程的proc结构中的相应项发送一个特定意义的信号。软中断必须等到接收进程执行时才能生效的。
中断,是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得cpu不得不暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后再返回原来被中断处继续执行的进程。其发生一般而言是“异步”的。换句话说就是在无法预测的情况下发生的。所以计算机的软硬件对于中断的相应反应完全是被动的。
陷阱,即由软件产生的中断,指处理机和内存内部产生的中断,它包括程序运算引起的各种错误,如地址非法、校验错误、页面失效等。它有专门的指令,如x86中的“intn”,在程序中是有意产生的。所以说陷阱是主动的、“同步”的。
2.管道
内容2:管道是 Linux 支持的最初 UNIX IPC 形式之一。所谓管道,是指能够连接一个读进程和一个进程以便相互传递数据的一个逻辑实体。对于管道两端的进程而言,管道就是一个文件,但它不是普
通的文件,不属于某种文件系统,而是单独构成一种文件系统,并且只存在于内存中。管道两端的进程通信时,一个进程向管道中写数据,管道另一端的进程读数据,写入的内容添加在管道缓冲区的末尾,读数据时从缓冲区的头部读。管道是半双工的,数据只能向一个方向流动,当需要双向通信时,需要建立起两个管道。
pipe()函数用于创建管道。创建的管道两端分别用两个文件描述符 fd[0]、fd[1]来描述,其中一
端称读端,由描述字 fd[0]表示;另一端称为写端,用描述字fd[1]来表示。创建管道后,只有创
建管道的进程及其子孙进程可以获得此文件描述符,才能利用该管道文件进行通信。一般文件的 I/O
函数都可以用于管道,如 close、read、write 等,故管道又称为 pipe 文件。从管道中读取数据时,如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为 0;当管道的写端存在时如果请求的字节数目大于缓冲 PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于缓冲 PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量),或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。向管道中写入数据时,Linux 不保证写入的原子性,管道缓冲区一旦有空闲区域,写进程就会试图向管道写入数据。如果读进程不读取管道缓冲区中的数据,那么写操作将一直阻塞。
管道的主要局限性正体现在它的特点上:
(1) 只支持单向数据流;
(2) 只能用于具有亲缘关系的进程之间;
(3) 没有名字;
(4) 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
(5) 管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格
式,比如多少字节算作一个消息(或命令、或记录)等等。
3.消息通信
内容3:消息队列用于运行于同一台机器上的一个进程给其它任意进程间发送一个消息,当一个进程收 到多个消息时,可将它们排列成一个消息队列。它和管道很相似,是一个在系统内核中用来保存消 息的队列,它在系统内核中以消息链表的形式出现。 消息队列机制使用两种重要的数据结构,一是消息首部,记录了一些与消息有关的信息,如消 息的类型、消息数据的字节数、指向消息缓冲区的指针、消息队列的链接指针等;二是消息队列头 表,其中的每一项作为一个消息队列的消息头,记录了消息队列的有关信息,如指向消息队列首部 和尾部的消息的指针、队列中消息的数目和消息的总字节数、队列所允许的消息数据字节和的总数、 及最后一次执行发送和接受操作的进程的标示符和时间等。
内容4:共享存储区(Share Memory)是UNIX系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。进程之间便可通过对共享存储区中数据的读、写来进行直接通信。图示列出二个进程通过共享一个共享存储区来进行通信的例子。其中,进程A将建立的共享存储区附接到自己的AA’区域,进程B将它附接到自己的BB’区域。
2)设计方案
内容1:
(1)编写程序,为父进程创建两个子进程,子进程与父进程之间使用软中断通信,父进程使用
kill()向子进程发出软中断信号,子进程分别调用不同的处理程序输出相应信息后终止。
(2)分析进程间使用软中断实现同步通信的机制和进程并发的原理。
(3)实验参考程序
内容2:
(1)编写程序,为父进程创建两个子进程,子进程与父进程之间使用软中断通信,父进程使用 kill()向子进程发出软中断信号,子进程分别调用不同的处理程序输出相应信息后终止。 (2)分析进程间使用软中断实现同步通信的机制和进程并发的原理。
内容3:
(1)编制程序:创建一个消息队列,写入一个消息后,读取并显示消息队列头部信息。
(2)(2)编制程序:在一个程序中,创建两个子进程,在两个子进程间使用消息队列机制实现通信并 显示发送和接收的信息;通信结束后,使用消息函数删除消息队列。
4.共享存储区通讯
(1)参考程序实现了一个程序的两个进程之间通过共享存储区实现通信,由于同一台机器中,多 个进程可以共享标示符,请实现两个程序,让两个程序分别创建进程 pid1 和 pid2,实现 pid1 和 pid2l 两个进程之间共享存储区通信。
(2)扩展实验内容 1,编程实现在一个程序中的两个进程不断向另外一个程序中的进程发送消息, 接收进程不断显示存储区中的内容,观察并分析输出的结果。
代码
内容1:
软中断
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/wait.h>
#include<sys/types.h>
int wait_flag=1;
void stop2()
{
wait_flag=0;
printf("son interruption \n");
}
void stop()
{
printf("interruption\n");
}
int main()
{
int p1,p2;
signal(3,stop);
while((p1=fork())==-1);
if (p1>0)
{
while((p2=fork())==-1);
if (p2>0)
{
sleep(5);
kill(p1,16);
kill(p2,17);
wait(0);
wait(0);
printf("Parent is killed!!\n");
exit(0);
}
else
{
signal(17,stop2);
while(wait_flag);
printf("Child p2 is killed!!\n");
exit(0);
}
}
else
{
signal(16,stop2);
while(wait_flag);
printf("Child p1 is killed!!\n");
exit(0);
}
return 0;
}
内容2:
管道
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
main()
{
int pid1,pid2;
int fd[2];
char outdata[100],indata[100];
if (pipe(fd)<0)
{
printf("creating pipe error \n");
return -1;
}
while((pid1=fork())==-1);
if(pid1==0)
{
lockf(fd[1],1,0);
sprintf(outdata,"Child Process pid1 is writing data! \n");
write(fd[1],outdata,50);
sleep(10);
lockf(fd[1],0,0);
exit(0);
}
else
{
while((pid2=fork())==-1);
if(pid2==0)
{
lockf(fd[1],1,0);
sprintf(outdata,"Child Process pid2 is writing data! \n");
write(fd[1],outdata,50);
sleep(10);
lockf(fd[1],0,0);
exit(0);
}
else
{
wait(0);
read(fd[0],indata,50);
printf("%s\n",indata);
wait(0);
read(fd[0],indata,50);
printf("%s\n",indata);
close(fd[0]);
close(fd[1]);
exit(0);
}
}
}
内容3:
消息通信
接收端:
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<sys/msg.h>
struct msg_st
{
long int msg_type;
char text[BUFSIZ];
};
int main()
{
int running= 1;
int msgid = -1;
struct msg_st data;
long int msgtype = 0;
msgid=msgget((key_t)1234,0666|IPC_CREAT);
if (msgid== -1)
{
fprintf(stderr,"msgget failed with error:%d\n",errno);
exit(EXIT_FAILURE);
}
while(running)
{
if(msgrcv(msgid,(void*)&data,BUFSIZ,msgtype,0)==-1)
{
fprintf(stderr,"msgrcv failed with errno:%d\n",errno);
exit(EXIT_FAILURE);
}
printf("You write:%s\n",data.text);
if(strncmp(data.text,"end",3)==0) {running=0;}
}
if(msgctl(msgid,IPC_RMID,0)== -1)
{
fprintf(stderr,"msgctl(IPC_RMID)failed \n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
发送端:
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/msg.h>
#include<errno.h>
#include<sys/ipc.h>
#define MAX_TEXT 512
struct msg_st
{
long int msg_type;
char text[MAX_TEXT];
};
int main()
{
int running = 1;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
msgid=msgget((key_t)1234,0666|IPC_CREAT);
if(msgid== -1)
{
fprintf(stderr,"msgget failed with error:%d\n",errno);
exit(EXIT_FAILURE);
}
while(running)
{
printf("Enter some text:");
fgets(buffer,BUFSIZ,stdin);
data.msg_type=1;
strcpy(data.text,buffer);
if(msgsnd(msgid,(void*)&data,MAX_TEXT,0)== -1)
{
fprintf(stderr,"msgsnd failed \n");
exit(EXIT_FAILURE);
}
if(strncmp(buffer,"end",3)== 0)
{running=0;}
sleep(1);
}
exit(EXIT_SUCCESS);
}
内容4:
共享存储区通讯
#include<sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/msg.h>
int main()
{
int shmid;
char *shmptr;
key_t key=1234;
pid_t pid;
pid =fork();
if(pid== 0)
{
shmid=shmget(key,1024,0600|IPC_CREAT);
shmptr=(char*)shmat(shmid,0,0);
printf("content:%s\n",shmptr);
shmctl(shmid,IPC_RMID,0);
printf("Child sleep 2s \n");
sleep(2);
exit(0);
}
else
{
shmid=shmget(key,1024,0600|IPC_CREAT|IPC_EXCL);
shmptr=(char*)shmat(shmid,0,0);
memcpy(shmptr,"hello world",sizeof("hello world"));
printf("parent sleep 2s \n");
sleep(2);
exit(0);
}
}