进程和进程间的通信
1、进程概念;
2、进程的控制:
(1)生成一个进程:fork
(2)进程的同步:wait waitpid
(3)进程的退出:exit _exit
(4)进程“脱胎换骨”:exec函数族
3、进程通信
(1)进程为什么需要通信?
(2)linux下进程如何通信
●早期的unix通信方式
无名管道;有名管道;信号
●sysem v的通信方式:共享内存、消息队列、信号量
●BSD的通信方式:socket
4、无名管道:适用于有血缘关系进程通信
小任务1:父进程通过无名管道向子进程发送字符串“Hello,you man!”,子进程接收到后显示出来,然后子进程退出,最后父进程退出。
(1)创建子进程:fork
(2)创建管道
#include
int pipe(int pipefd[2]);
参数说明(当管道创建成功后):
pipefd[0]:读端的文件描述符;
pipefd[1]:写端的文件描述
返回值:0表示创建成功,-1表示创建失败
(3)父亲写管道
write
(4)儿子读管道
read
(5)父亲等待儿子退出
wait
参考代码:
#include
#include
#include
#include
#include
int main()
{
int pid;
int pipefd[2];
int ret;
char buf[]="Hello,young man!";
ret=pipe(pipefd);//创建管道(1)
if(ret<0)
{
perror("Failed to create pipe:");
return -1;
}
pid=fork();
//能够把(1)语句放此注释的下一样??
if(pid<0)
{
perror("Failed to create child process:");
return -1;
}
if(pid>0)
{
close(pipefd[0]);//父进程中关闭无关的读端
write(pipefd[1],buf,strlen(buf));
wait(NULL);
printf("Parent process exit!\n");
}
else
{
char receive_buf[100];
int count;
close(pipefd[1]);//子进程中关闭无关的写端
count=read(pipefd[0],receive_buf,100);
if(count>0)
{
receive_buf[count]='\0';
printf("Child process receive a string:%s\n",receive_buf);
}
printf("Child process exit!\n");
}
return 0;
}
5、有名管道(fifo)
(1)文件系统中可见,可以通过mkfifo 命令来创建一个有名管道
eg: mkfifo -m 0666 myfifo
(2)有名管道的使用跟普通文件一样:open read write close,不用使用lseek!!!!
任务2:
进程1通过有名管道把键盘输入字符串发送给进程2,进程2收到后显
示出来,当收到字符串“exit”是退出程序!!
(1)手工建立一个有名管道myfifo
(2)打开管道;
(3)读写管道
注意:有名管道的读写跟普通文件没有什么区别!!
参考代码:
//fifoReader.c
#include
#include
#include
#include
#include
int main()
{
int fd;
char buf[128];
fd=open("/home/gec/myfifo",O_RDONL Y);
if(fd<0)
{
perror("Failed to open fifo:");
return -1;
}
while(1)
{
int count;
count=read(fd,buf,127);
if(count>0)
{
buf[count]=0;
printf("fifoReader receive a string:%s\n",buf);
}
if(strncmp(buf,"exit",4)==0)
{
break;
}
}
close(fd);
return 0;
}
//fifoWrite.c
#include
#include
#include
#include
#include
int main()
{
int fd;
char buf[128];
fd=open("/home/gec/myfifo",O_WRONL Y);
if(fd<0)
{
perror("Failed to open fifo:");
return -1;
}
while(1)
{
fgets(buf,128,stdin);
write(fd,buf,strlen(buf));
if(strncmp(buf,"exit",4)==0)
{
break;
}
}
close(fd);
return 0;
}
6、信号
(1)可以用命令kill -l列出当前系统所支持的信号
(2)对于很多信号,进程都有默认的处理方式;
(3)信号的发送
#include
#include
int kill(pid_t pid, int sig);
(4)信号的处理:当进程接收一个信号后如何与“一段代码关联起来”
模版:
//信号处理函数
void 你自己命名的信号处理函数名(int sig)//sig:信号值
{
//对信号的处理
}
//在程序的某一个地方把信号处理函数和信号关联起来,其“后果”就是进程一旦接收到该信号,就会导致该信号处理函数的调用!!
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
在需要关联的时候只需要调用signal函数就可以了!!
信号:signum--------------------信号处理函数:handler
小任务3:
用触发信号的方式每2秒钟向屏幕打印“Hello,world!”
(1)每隔2秒钟触发一个闹钟信号SIGALRM
alarm(2);
(2)在信号处理函数里完成屏幕大打印:
void alarm_handler(int sig)
{
if(sig==SIGALRM)
{
printf(“Hello,world!\n”);\
alarm(2);
}
}
(3)在你的程序的某个地方添加如下语句
signal(SIGALRM, alarm_handler);
参考代码:
#include
#include
#include
#include
void alarm_handler(int sig)
{
if(sig==SIGALRM)
{
printf("Hello,world!\n");
alarm(2);
}
}
int main()
{
signal(SIGALRM,alarm_handler);//此语句的作用:一旦进程接收到SIGALRM信号,就会导致alarm_handler的调用
alarm(2);//此语句的作用:2秒钟后会向调用进程发送SIGALRM信号
while(1);
return 0;
}
小任务4:(练习kill的使用)
当进程2收到进程1发出的SIGUSR1信号后停止向屏幕输出“Hello,world!\n”. 进程2的执行格式可以如下:
./进程1 进程2的进程号
参考代码
//p1.c
#include
#include
#include
#include
int main(int argc,char **argv)
{
int dest_id;
int ret;
if(argc<2)
{
printf("Argument too few!\n");
return 0;
}
dest_id=atoi(argv[1]);//将参数指针型转换成整型;
//sscanf(argv[1],"%d",&dest_id);也可用这个语句实现数据类型转化;
printf("The pid of destination process id %d\n",dest_id);
ret=kill(dest_id,SIGUSR1);
if(ret<0)
printf("Failed to send signal.\n");
return 0;
}
//p2.c
#include
#include
#include
int flag=1;
void sigusr1_handler(int sig)
{
if(sig==SIGUSR1)
{
flag=0;
}
}
int main()
{
signal(SIGUSR1,sigusr1_handler);建立与信号相关联的回调函数关系;
while(flag==1)
{
printf("Hello,world!\n");
sleep(2);
}
return 0;
}
7、共享内存
8、共享内存使用的步骤
(1)创建共享内存块的一个外键
#include
#include
key_t ftok(const char *pathname, int proj_id);
注意:pathname必须是系统中真实存在的而且稳定的路径,一般proj_id用一个ascii字符来代替
(2)获取或者创建共享内存块
#include
#include
int shmget(key_t key, size_t size, int shmflg);
注意:
第一个参数一般为在步骤1所创建或获取的外键,如果你的共享内存块是一个私有共享内存块,可以选择为IPC_PRIV ATE;
第二个参数为所创建或获取的共享内存块的大小(以字节为单位);
第三个参数所为所创建或获取共享内存块的权限:
IPC_CREAT: 当用key所对应共享内存不存在时则创建它;
IPC_EXCL:当空享内存块存在则创建失败;
0666:共享内块的权限;
该函数的返回值,当创建成功是为共享内存块的内部标识!
(3)共享内存块的映射
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
把shmid所标识的共享内存块映射调用进程的地址空间,第2、3参数一般为0;当映射成功是返回共享内存块在用户空间地址,失败则为-1;
(3)撤销共享内存块的映射
#include
#include
int shmdt(const void *shmaddr);
当进程不需要对共享内存块进行读写的时候调用该函数!!
(4)删除共享内存块
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
一般的调用格式:
shmctl(shmid,IPC_RMID,NULL);
小任务:
进程1把从键盘获取的字符串通过共享内存发送给进程2,进程接手后显示出来,当接收到”exit”时退出。需要通过信号处理进程1、2的同步关系:当进程往共享内写字符串后给进程2发送信号。
提示:
共享内块的数据定义:
struct shm_struct
{
int writerProcessId;
int readerProcessId;
char buf[512];
};
参考代码:
//shmWriter.c
#include
#include
#include
#include
#include
#include
//定义结构体以格式化共享内存块,并声明了该结构体类型指针变量pShm
struct shm_struct
{
int writerProcessId;
int readerProcessId;
char buf[512];
}*pShm;
int main()
{
int shmid;
key_t key=ftok("/home",'a');//获取共享内存块外键
printf("Key=%d\n",key);
shmid=shmget(key,sizeof(struct shm_struct),IPC_CREA T|0666);//获取共享内存块标示符
if(shmid<0)
{
perror("Failed to create share memory!\n");
return -1;
}
printf("shmid=%d\n",shmid);
pShm=(struct shm_struct*)shmat(shmid,0,0);//映射共享内存块
bzero(pShm,sizeof(struct shm_struct)); //把共享内存块清0
pShm->writerProcessId=getpid();//初始化内存块的写者pid
while(1)
{
fgets(pShm->buf,512,stdin);//从键盘获取字符串
if(pShm->readerProcessId!=0)
{
kill(pShm->readerProcessId,SIGUSR1);//给读者发信号表示已经写了一个新的字符串到共享内存块
}
}
return 0;
}
//shmReader.c
#include
#include
#include
#include
#include
#include
struct shm_struct
{
int writerProcessId;
int readerProcessId;
char buf[512];
}*pShm;
int flag=0;
void can_read_shm(int sig)
{
flag=1;
}
int main()
{
int shmid;
key_t key=ftok("/home",'a');
printf("Key=%d\n",key);
shmid=shmget(key,sizeof(struct shm_struct),IPC_CREAT|0666);
if(shmid<0)
{
perror("Failed to create share memory!\n");
return -1;
}
printf("shmid=%d\n",shmid);
pShm=(struct shm_struct*)shmat(shmid,0,0);
pShm->readerProcessId=getpid();
signal(SIGUSR1,can_read_shm);
while(1)
{
if(flag==1)
{
flag=0;
printf("%s",pShm->buf);
if(strncmp(pShm->buf,"exit",4)==0)
break;
}
}
pShm->readerProcessId=0;
return 0;
}
9.消息队列
相关函数:msgget msgsnd msgrcv msgctl
注意:
(1)消息缓冲区的最大长度(含消息类型)的最大长度不要超过4096字节;(2)msgsnd msgrcv的正文长度参数是以字节为单位的;
(3)定义消息结构体时,消息类型一定最开始的成员:
错误的定义:
struct message_buf
{
char buf[512];
long msgType;
};
正确的定义:
struct message_buf
{
long msgType;
char buf[512];
};
小任务:
基于消息队列的通信方式实现一个服务器/客户端模式的计算系统:
(1)服务端从消息队列读取需要计算的两个整数,求和后把结果同通过消息队列返回客户端;
(2)客户端从键盘读取两个整数,通过消息队列发送服务器,接收到计算结果后显示出来
(3)要求服务端能同时处理多个客户端的请求
分析:
服务器端:
(1)初始化;
(2)从消息队列获取消息;
(3)求和计算;
(4)给客户端发送和消息
(5)转(2)
客户端:
(1)初始化;
(2)从键盘获取两个整数;
(3)通过消息队列发送两个整数给服务器;
(4)接收服务器端和消息;
(5)转(2)
参考代码:
//msgServer.c
#include
#include
#include
#include
#include
#include "comm.h"(此头文件包含结构体struct c2s_Message 、struct s2s_message)
int main()
{
int msgid;
int sum;
struct c2s_message c2sMessage;
struct s2c_message s2cMessage;
key_t key=ftok("/usr/lib",'a');创建外键
msgid=msgget(key,IPC_CREAT|0666);建立消息队列
s2cMessage.msgType=2;消息类型为2
while(1)
{
msgrcv(msgid,(void*)&c2sMessage,sizeof(struct c2s_message)-sizeof(long),1,0);
sum=c2sMessage.x+c2sMessage.y;
s2cMessage.sum=sum;
msgsnd(msgid,(void*)&s2cMessage,sizeof(struct s2c_message)-sizeof(long),0);
}
return 0;
}
//msgClient.c
#include
#include
#include
#include
#include
#include "comm.h"
int main()
{
int msgid;
struct c2s_message c2sMessage;
struct s2c_message s2cMessage;
key_t key=ftok("/usr/lib",'a');
msgid=msgget(key,IPC_CREAT|0666);
c2sMessage.msgType=1;
while(1)
{
scanf("%d%d",&c2sMessage.x,&c2sMessage.y);
msgsnd(msgid,(void*)&c2sMessage,sizeof(struct c2s_message)-sizeof(long),0);发送消息
msgrcv(msgid,(void*)&s2cMessage,sizeof(struct s2c_message)-sizeof(long),2,0);接收消息
printf("sum=%d\n",s2cMessage.sum);
}
return 0;
}
进程间通信的四种方式
一、剪贴板 1、基础知识 剪贴板实际上是系统维护管理的一块内存区域,当在一个进程中复制数据时,是将这个数据放到该块内存区域中,当在另一个进程中粘贴数据时,是从该内存区域中取出数据。 2、函数说明: (1)、BOOL OpenClipboard( ) CWnd类的OpenClipboard函数用于打开剪贴板。若打开剪贴板成功,则返回非0值。若其他程序或当前窗口已经打开了剪贴板,则该函数返回0值,表示打开失败。若某个程序已经打开了剪贴板,则其他应用程序将不能修改剪贴板,直到前者调用了CloseClipboard函数。 (2)、BOOL EmptyClipboard(void) EmptyClipboard函数将清空剪贴板,并释放剪贴板中数据的句柄,然后将剪贴板的所有权分配给当前打开剪贴板的窗口。 (3)、HANDLE SetClipboardData(UINT uFormat, HANDLE hMem) SetClipboardData函数是以指定的剪贴板格式向剪贴板上放置数据。uFormat指定剪贴板格式,这个格式可以是已注册的格式,或是任一种标准的剪贴板格式。CF_TEXT表示文本格式,表示每行数据以回车换行(0x0a0x0d)终止,空字符作为数据的结尾。hMem指定具有指定格式的数据的句柄。hMem参数可以是NULL,指示采用延迟提交技术,则该程序必须处理WM_RENDERFORMA T和WM_RENDERALLFORMATS消息。应用程序在调用SetClipboardData函数之后,就拥有了hMem参数所标识的数据对象,该应用程序可以读取该数据对象,但在应用程序调用CloseClipboard函数之前,它不能释放该对象的句柄,或者锁定这个句柄。若hMem标识了一个内存对象,那么这个对象必须是利用GMEM_MOVEABLE标志调用GlobalAlloc函数为其分配内存。 注意:调用SetClipboardData函数的程序必须是剪贴板的拥有者,且在这之前已经打开了剪贴板。 延迟提交技术:当一个提供数据的进程创建了剪贴板数据之后,直到其他进程获取剪贴板数据之前,这些数据都要占据内存空间。若在剪贴板上放置的数据过大,就会浪费内存空间,降低对资源的利用率。为了避免这种浪费,就可以采用延迟提交计数,也就是由数据提供进程先提供一个指定格式的空剪贴板数据块,即把SetClipboardData函数的hMem参数设置为NULL。当需要获取数据的进程想要从剪贴板上得到数据时,操作系统会向数据提供进程发送WM_RENDERFORMA T消息,而数据提供进程可以响应这个消息,并在此消息的响应函数中,再一次调用SetClipboardData函数,将实际的数据放到剪贴板上。当再次调用SetClipboardData函数时,就不再需要调用OpenClipboard函数,也不再需要调用EmptyClipboard函数。也就是说,为了提高资源利用率,避免浪费内存空间,可以采用延迟提交技术。第一次调用SetClipboardData函数时,将其hMem参数设置为NULL,在剪贴板上以指定的剪贴板格式放置一个空剪贴板数据块。然后直到有其他进程需要数据或自身进程需要终止运行时再次调用SetClipboardData函数,这时才真正提交数据。 (4)、HGLOBAL GlobalAlloc( UINT uFlags,SIZE_T dwBytes); GlobalAlloc函数从堆上分配指定数目的字节。uFlags是一个标记,用来指定分配内存的方式,uFlags为0,则该标记就是默认的GMEM_FIXED。dwBytes指定分配的字节数。
Windows进程间各种通信方式浅谈
Windows进程间各种通信方式浅谈 1、Windows进程间通信的各种方法 进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。 多进程/多线程是Windows操作系统的一个基本特征。Microsoft Win32应用编程接口(Application Programming Interface, API) 提供了大量支持应用程序间数据共享和交换的机制,这些机制行使的活动称为进程间通信(InterProcess Communication, IPC),进程通信就是指不同进程间进行数据共享和数据交换。 正因为使用Win32 API进行进程通信方式有多种,如何选择恰当的通信方式就成为应用开发中的一个重要问题, 下面本文将对Win32中进程通信的几种方法加以分析和比较。 2、进程通信方法 2.1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容。 Win32 API允许多个进程访问同一文件映射对象,各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针,不同进程就可以读或修改文件的内容,实现了对文件中数据的共享。 应用程序有三种方法来使多个进程共享一个文件映射对象。 (1)继承:第一个进程建立文件映射对象,它的子进程继承该对象的句柄。 (2)命名文件映射:第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外,第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。 (3)句柄复制:第一个进程建立文件映射对象,然后通过其它IPC机制(有名管道、
操作系统进程通信练习及答案
进程同步与通信练习题 (一)单项选择题 1?临界区是指()。A?并发进程中用于实现进程互斥的程序段 B ?并发进程中用于实现进程同步的程序段C?并发进程中用户实现进程通信的程序段D?并发进程中与共享变量有关的程序段 2?相关临界区是指()°A. —个独占资源B ?并发进程中与共享变量有关的程序段 c ?一 个共享资源 D ?并发进程中涉及相同变量的那些程序段 3?管理若干进程共享某一资源的相关临界区应满足三个要求,其中()不考虑。A 一个进 程可以抢占己分配给另一进程的资源B?任何进程不应该无限地逗留在它的临界区中 c ? 一次最多让一个进程在临界区执行 D .不能强迫一个进程无限地等待进入它的临界区 4、()是只能由P和v操作所改变的整型变量。A共享变量B ?锁c整型信号量 D ?记录型信号量 5.对于整型信号量,在执行一次P操作时,信号量的值应()。 A .不变B.加1 C减 I D .减指定数值 6?在执行v操作时,当信号量的值()时,应释放一个等待该信号量的进程。A>0 B.<0 c.>=0 D.<=0 操作必须在屏蔽中断下执行,这种不可变中断的过程称为()。A初始化程序B ?原语c ?子 程序 D 控制模块 &进程间的互斥与同步分别表示了各进程间的()。A ?竞争与协作 B .相互独立与相 互制约 c .不同状态 D .动态性与并发性 9并发进程在访问共享资源时的基本关系为()。A ?相互独立与有交往的 B ?互斥与同步 c 并行执行与资源共享 D 信息传递与信息缓冲 10在进程通信中,()常用信件交换信息。 A 低级通信 B 高级通信 c 消息通信 D 管道通信II?在间接通信时,用send(N , M)原语发送信件,其中N表示()。A.发送信件的进程名 B 接收信件的进程名 C 信箱名 D 信件内容 12?下列对线程的描述中,()是错误的。A不同的线程可执行相同的程序 B ?线程是资 源分配单位 c 线程是调度和执行单位 D 同一进程中的线程可共享该进程的主存空间 13?实现进程互斥时,用()对应,对同一个信号量调用Pv操作实现互斥。A ? 一个信号量与一个临界区 B 一个信号量与—个相关临界区 c 一个信号量与一组相关临界区 D 一个信号量与一个消息14实现进程同步时,每一个消息与一个信号量对应,进程()可把不同的消息发送出去。 A.在同一信号量上调用P操作B在不同信号量上调用P操作c ?在同一信号量上调用v 操作D ?在不同信号量上调用v操作 (二)填空题 1 目前使用的计算机的基本特点是处理器___________ 执行指令。2进程的______ 是指进程在顺 序处理器上的执行是按顺序进行的。 3 当一个进程独占处理器顺序执行时,具有_______________ 和_____ 两个特性。 4 进程的封闭性是指进程的执行结果只取决于___________ ,不受外界影响。5进程的可再现性是指当进程再次重复执行时,必定获得__________ 的结果。 6 一个进程的工 作在没有全部完成之前,另一个进程就可以开始工作,则称这些进程为________ . 7 若系统中 存在一组可同时执行的进程,则就说该组进程具有 _________ 。8 如果—个进程的执行不影 响其他进程的执行,且与其他进程的进展情况无关,则说这些并发进程相互之间是______ 的。9如果一个进程的执行依赖其他进程的进展情况,则说这些并发进程相互之间是 __________ 10 有交往的并发进程一定_________ 某些资源。11 有交往的进程执行时可能产生与时间有 关的错误,造成不正确的因素与进程 _________ 、 _____ 和外界的影响有关。12 .对 _______ 的使用不受限制,这是使有交往的并发进程执行时出现与时间有关的错误的根本原因。13 .临界区是指并发进程中与 _____________ 有关的程序段。14 ._______ 是指并发进程中涉及到相同变量
进程间通信实验报告
进程间通信实验报告 班级:10网工三班学生姓名:谢昊天学号:1215134046 实验目的和要求: Linux系统的进程通信机构 (IPC) 允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉Linux支持的消息通讯机制及信息量机制。 实验内容与分析设计: (1)消息的创建,发送和接收。 ①使用系统调用msgget (), msgsnd (), msgrev (), 及msgctl () 编制一长度为1k 的消息的发送和接收程序。 ②观察上面的程序,说明控制消息队列系统调用msgctl () 在此起什么作用? (2)共享存储区的创建、附接和段接。 使用系统调用shmget(),shmat(),sgmdt(),shmctl(),编制一个与上述功能相同的程序。(3)比较上述(1),(2)两种消息通信机制中数据传输的时间。 实验步骤与调试过程: 1.消息的创建,发送和接收: (1)先后通过fork( )两个子进程,SERVER和CLIENT进行通信。 (2)在SERVER端建立一个Key为75的消息队列,等待其他进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER 。SERVER每接收到一个消息后显示一句“(server)received”。 (3)CLIENT端使用Key为75的消息队列,先后发送类型从10到1的消息,然后退出。最后的一个消息,既是 SERVER端需要的结束信号。CLIENT每发送一条消息后显示一句“(client)sent”。 (4)父进程在 SERVER和 CLIENT均退出后结束。 2.共享存储区的创建,附接和断接: (1)先后通过fork( )两个子进程,SERVER和CLIENT进行通信。 (2)SERVER端建立一个KEY为75的共享区,并将第一个字节置为-1。作为数据空的标志.等待其他进程发来的消息.当该字节的值发生变化时,表示收到了该消息,进行处理.然后再次把它的值设为-1.如果遇到的值为0,则视为结束信号,取消该队列,并退出SERVER.SERVER 每接收到一次数据后显示”(server)received”. (3)CLIENT端建立一个为75的共享区,当共享取得第一个字节为-1时, Server端空闲,可发送请求. CLIENT 随即填入9到0.期间等待Server端再次空闲.进行完这些操作后, CLIENT退出. CLIENT每发送一次数据后显示”(client)sent”. (4)父进程在SERVER和CLIENT均退出后结束。 实验结果: 1.消息的创建,发送和接收: 由 Client 发送两条消息,然后Server接收一条消息。此后Client Server交替发送和接收消息。最后一次接收两条消息。Client 和Server 分别发送和接收了10条消息。message 的传送和控制并不保证完全同步,当一个程序不再激活状态的时候,它完全可能继续睡眠,造成上面现象。在多次send message 后才 receive message.这一点有助于理解消息转送的实现机理。
实验三 软中断通信
实验三软中断通信 实验目的 1、了解什么是信号 2、熟悉LINUX系统中进程之间软中断通信的基本原理 实验内容 1、编写程序:用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止: Child process1 is killed by parent! Child process2 is killed by parent! 父进程等待两个子进程终止后,输出如下的信息后终止: Parent process is killed! 2、分析利用软中断通信实现进程同步的机理 实验指导 一、信号 1、信号的基本概念 每个信号都对应一个正整数常量(称为signal number,即信号编号。定义在系统头文件
进程同步与通信作业习题与答案
第三章 一.选择题(50题) 1.以下_B__操作系统中的技术是用来解决进程同步的。 A.管道 B.管程 C.通道 2.以下_B__不是操作系统的进程通信手段。 A.管道 B.原语 C.套接字 D.文件映射 3.如果有3个进程共享同一程序段,而且每次最多允许两个进程进入该程序段,则信号量的初值应设置为_B__。 4.设有4个进程共享一个资源,如果每次只允许一个进程使用该资源,则用P、V操作管理时信号量S的可能取值是_C__。 ,2,1,0,-1 ,1,0,-1,-2 C. 1,0,-1,-2,-3 ,3,2,1,0 5.下面有关进程的描述,是正确的__A__。 A.进程执行的相对速度不能由进程自己来控制 B.进程利用信号量的P、V 操作可以交换大量的信息 C.并发进程在访问共享资源时,不可能出现与时间有关的错误 、V操作不是原语操作 6.信号灯可以用来实现进程之间的_B__。 A.调度 B.同步与互斥 C.同步 D.互斥 7.对于两个并发进程都想进入临界区,设互斥信号量为S,若某时S=0,表示_B__。 A.没有进程进入临界区 B.有1个进程进入了临界区 C. 有2个进程进入了临界区 D. 有1个进程进入了临界区并且另一个进程正等待进入 8. 信箱通信是一种_B__方式 A.直接通信 B.间接通信 C.低级通信 D.信号量 9.以下关于临界区的说法,是正确的_C__。
A.对于临界区,最重要的是判断哪个进程先进入 B.若进程A已进入临界区,而进程B的优先级高于进程A,则进程B可以 打断进程A而自己进入临界区 C. 信号量的初值非负,在其上只能做PV操作 D.两个互斥进程在临界区内,对共享变量的操作是相同的 10. 并发是指_C__。 A.可平行执行的进程 B.可先后执行的进程 C.可同时执行的进程 D.不可中断的进程 11. 临界区是_C__。 A.一个缓冲区 B.一段数据区 C.一段程序 D.栈 12.进程在处理机上执行,它们的关系是_C__。 A.进程之间无关,系统是封闭的 B.进程之间相互依赖相互制约 C.进程之间可能有关,也可能无关 D.以上都不对 13. 在消息缓冲通信中,消息队列是一种__A__资源。 A.临界 B.共享 C.永久 D.可剥夺 14. 以下关于P、V操作的描述正确的是__D_。 A.机器指令 B. 系统调用 C.高级通信原语 D.低级通信原语 15.当对信号量进行V源语操作之后,_C__。 A.当S<0,进程继续执行 B.当S>0,要唤醒一个就绪进程 C. 当S<= 0,要唤醒一个阻塞进程 D. 当S<=0,要唤醒一个就绪 16.对临界区的正确论述是__D_。 A.临界区是指进程中用于实现进程互斥的那段代码 B. 临界区是指进程中用于实现进程同步的那段代码 C. 临界区是指进程中用于实现进程通信的那段代码 D. 临界区是指进程中访问临界资源的那段代码 17. __A__不是进程之间的通信方式。 A.过程调用 B.消息传递 C.共享存储器 D.信箱通信 18. 同步是指进程之间逻辑上的__A__关系。
操作系统之进程(生产者_消费者)实验报告
操作系统实验报告 ——生产者和消费者问题 姓名:学号:班级: 一、实验内容 1、模拟操作系统中进程同步和互斥; 2、实现生产者和消费者问题的算法实现; 二、实验目的 1、熟悉临界资源、信号量及PV操作的定义与物理意义; 2、了解进程通信的方法; 3、掌握进程互斥与进程同步的相关知识; 4、掌握用信号量机制解决进程之间的同步与互斥问题; 5、实现生产者-消费者问题,深刻理解进程同步问题; 三、实验题目 在Windows操作系统下用C语言实现经典同步问题:生产者—消费者,具体要求如下: (1)一个大小为10的缓冲区,初始状态为空。 (2)2个生产者,随机等待一段时间,往缓冲区中添加数据,若 缓冲区已满,等待消费者取走数据之后再添加,重复10次。 (3)2个消费者,随机等待一段时间,从缓冲区中读取数据,若 缓冲区为空,等待生产者添加数据之后再读取,重复10次。 四、思想 本实验的主要目的是模拟操作系统中进程同步和互斥。在系统进程并发执行异步推进的过程中,由于资源共享和进程间合作而造成进程间相互制约。进程间的相互制约有两种不同的方式。 (1)间接制约。这是由于多个进程共享同一资源(如CPU、共享
输入/输出设备)而引起的,即共享资源的多个进程因系统协调使用资源而相互制约。 (2)直接制约。只是由于进程合作中各个进程为完成同一任务而造成的,即并发进程各自的执行结果互为对方的执行条件,从而限制各个进程的执行速度。 生产者和消费者是经典的进程同步问题,在这个问题中,生产者不断的向缓冲区中写入数据,而消费者则从缓冲区中读取数据。生产者进程和消费者对缓冲区的操作是互斥,即当前只能有一个进程对这个缓冲区进行操作,生产者进入操作缓冲区之前,先要看缓冲区是否已满,如果缓冲区已满,则它必须等待消费者进程将数据取出才能写入数据,同样的,消费者进程从缓冲区读取数据之前,也要判断缓冲区是否为空,如果为空,则必须等待生产者进程写入数据才能读取数据。 在本实验中,进程之间要进行通信来操作同一缓冲区。一般来说,进程间的通信根据通信内容可以划分为两种:即控制信息的传送与大批量数据传送。有时,也把进程间控制在本实验中,进程之间要进行通信来操作同一缓冲区。一般来说,进程间的通信根据通信内容可以划分为两种:即控制信息的传送与大批量数据传送。有时,也把进程间控制信息的交换称为低级通信,而把进程间大批量数据的交换称为高级通信。 目前,计算机系统中用得比较普遍的高级通信机制可分为3大类:共享存储器系统、消息传递系统及管道通信系统。 ?共享存储器系统 共享存储器系统为了传送大量数据,在存储器中划出一块共享存储区,诸进程可通过对共享存储区进行读数据或写数据以实现通信。
进程之间的通信实验
实验:进程之间的通信管道 1.Pipe函数与进程通信 下面实验为使用管道进行父子进程间通信。程序首先判断参数是否合法,因为输入的字符将从父进程通过发送到子进程中。然后,调用pipe函数创建父子进程用于通信的管道。使用fork函数创建子进程时,子进程会获得与父进程相同的资源,其中包括文件描述符信息。因此,调用fork函数须在pipe函数调用前。 当父子进程通过管道进行通信时,files[1]为用于数据写入的文件描述符.因此,在子进程中,要读取管道中的数据可以调用read函数,而读取得文件描述符为files[0]。对于父进程而言,写入数据需要调用write 函数,要写入的文件描述为files[1]。 #include
进程软中断通信资料
进程软中断通信 【预备知识】 进程软中断通信涉及的系统调用描述如下。 1.kill() 进程用kill()向一个进程或一组进程发送一个信号。系统调用格式为int kill(pid,sig)。其中,pid是一个或一组进程的标识符,sig是要发送的软中断信号。信号的发送分如下三种情况。 pid>0时,核心将信号发送给进程pid。 pid=0时,核心将信号发送给与发送进程同组的所用进程。 pid=-1时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。 2.signal(sig,function) 接收信号的程序用signal()来实现对处理方式的预置,允许调用进程控制软中断信号。系统调用格式为signal(sig function),此时需包含头文件signal.h。其中,sig用于指定信号的类型,sig为0则表示没有收到任何信号,其余类型如表所示。 调用函数使用如下头文件: #include
第二章-操作系统进程(练习题答案)
第二章进程管理 1.操作系统主要是对计算机系统全部 (1) 进行管理,以方便用户、提高计算机使 用效率的一种系统软件。它的主要功能有:处理机管理、存储管理、文件管理、 (2) 管 理和设备管理等。Windows和Unix是最常用的两类操作系统。前者是一个具有图形界面的 窗口式的 (3) 系统软件,后者是一个基本上采用 (4) 语言编制而成的 的系统软件。在 (5) 操作系统控制下,计算机能及时处理由过程控制反馈的信息 并作出响应。 供选答案: (1): A. 应用软件 B. 系统软硬件 C. 资源 D. 设备 (2): A. 数据 B. 作业 C. 中断 D. I/O (3): A. 分时 B. 多任务 C. 多用户 D. 实时 (4): A. PASCAL B. 宏 C. 汇编 D. C (5): A. 网络 B. 分时 C. 批处理 D. 实时 答案:CBBDD 2.操作系统是对计算机资源进行的 (1) 系统软件,是 (2) 的接口。 在处理机管理中,进程是一个重要的概念,它由程序块、 (3) 和数据块三部 分组成,它有3种基本状态,不可能发生的状态转换是 (4) 。 虚拟存储器的作用是允许程序直接访问比内存更大的地址空间,它通常使用 (5) 作为它的一个主要组成部分。 供选答案: (1): A. 输入和输出 B. 键盘操作 C. 管理和控制 D. 汇编和执行 (2): A. 软件和硬件 B. 主机和外设 C. 高级语言和机器语言 D. 用户和计算机 (3): A. 进程控制块 B. 作业控制块 C. 文件控制块 D. 设备控制块 (4): A. 运行态转换为就绪态 B. 就绪态转换为运行态 C. 运行态转换为等待态 D. 等待态转换为运行态 (5): A. 软盘 B. 硬盘 C. CDROM D. 寄存器 答案:CDADB 3.在计算机系统中,允许多个程序同时进入内存并运行,这种方法称为 D。 A. Spodling技术 B. 虚拟存储技术 C. 缓冲技术 D. 多道程序设计技术 4.分时系统追求的目标是 C。 A. 高吞吐率 B. 充分利用内存 C. 快速响应 D. 减少系统开销 5.引入多道程序的目的是 D。
Linux下的进程间通信-详解
Linux下的进程间通信-详解 详细的讲述进程间通信在这里绝对是不可能的事情,而且笔者很难有信心说自己对这一部分内容的认识达到了什么样的地步,所以在这一节的开头首先向大家推荐著 名作者Richard Stevens的著名作品:《Advanced Programming in the UNIX Environment》,它的中文译本《UNIX环境高级编程》已有机械工业出版社出版,原文精彩,译文同样地道,如果你的确对在Linux下编程有浓 厚的兴趣,那么赶紧将这本书摆到你的书桌上或计算机旁边来。说这么多实在是难抑心中的景仰之情,言归正传,在这一节里,我们将介绍进程间通信最最初步和最 最简单的一些知识和概念。 首先,进程间通信至少可以通过传送打开文件来实现,不同的进程通过一个或多个文件来传递信息,事实上,在很多应用系统里,都使用了这种方法。但一般说来, 进程间通信(IPC:InterProcess Communication)不包括这种似乎比较低级的通信方法。Unix系统中实现进程间通信的方法很多,而且不幸的是,极少方法能在所有的Unix系 统中进行移植(唯一一种是半双工的管道,这也是最原始的一种通信方式)。而Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信 方法:管道、消息队列、共享内存、信号量、套接口等等。下面我们将逐一介绍。 2.3.1 管道 管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。 无名管道由pipe()函数创建: #include
Linux进程通信实验报告
Linux进程通信实验报告 一、实验目的和要求 1.进一步了解对进程控制的系统调用方法。 2.通过进程通信设计达到了解UNIX或Linux系统中进程通信的基本原理。 二、实验内容和原理 1.实验编程,编写程序实现进程的管道通信(设定程序名为pipe.c)。使 用系统调用pipe()建立一条管道线。而父进程从则从管道中读出来自 于两个子进程的信息,显示在屏幕上。要求父进程先接受子进程P1 发来的消息,然后再接受子进程P2发来的消息。 2.可选实验,编制一段程序,使其实现进程的软中断通信(设定程序名为 softint.c)。使用系统调用fork()创建两个子进程,再用系统调用 signal()让父进程捕捉键盘上来的中断信号(即按Del键),当父进程 接受这两个软中断的其中一个后,父进程用系统调用kill()向两个子 进程分别发送整数值为16和17的软中断信号,子进程获得对应软中 断信号后分别输出相应信息后终止。 三、实验环境 一台安装了Red Hat Linux 9操作系统的计算机。 四、实验操作方法和步骤 进入Linux操作系统,利用vi编辑器将程序源代码输入并保存好,然后 打开终端对程序进行编译运行。 五、实验中遇到的问题及解决 六、实验结果及分析 基本实验 可选实验
七、源代码 Pipe.c #include"stdio.h" #include"unistd.h" main(){ int i,j,fd[2]; char S[100]; pipe(fd); if(i=fork==0){ sprintf(S,"child process 1 is sending a message \n"); write(fd[1],S,50); sleep(3); return; } if(j=fork()==0){ sprintf(S,"child process 2 is sending a message \n"); write(fd[1],S,50); sleep(3); return;
操作系统实验进程的通信
(操作系统原理和linux操作系统相结合的实验) 实验二进程的通信 一实验目的 1 学会使用vi编辑器编辑C语言程序 2 学会Linux环境下gcc的使用 3 学会调试工具GDB的使用 二实验原理 1 利用linux提供的进程通信的系统调用设计进程通信程序,加深对进程通信概念的理解。 2 体会进程通信的方法和效果。 三实验环境 PC机1台,Windows操作系统和其上的虚拟Linux操作系统。 四实验步骤 1.管道通信 (1)编写一个程序。父进程创建一个子进程和一个无名管道fd,由子进程向管道写入信息“This is a message”,然后终止执行;父进程接收到子进程终止信号后从管道中读出并显示信息后结束。 #include
{ wait(0); //等待子进程终止 read(fd[0],outpipe,50); //从管道读信息到读缓冲区 printf("%s\n",outpipe); //显示读到的信息 exit(0); } } (2)父进程创建两个子进程,父子进程之间利用管道进行通信。要求能显示父进程、子进程各自的信息,体现通信效果。(源程序pipe_1.c) #include
进程间的通信
实验三进程间的通信 【实验类型】 综合性实验 【目的要求】 学习如何利用管道机制、消息缓冲队列、共享存储区机制进行进程间的通讯,并加深对上述通信机制的理解。 【内容提要】 1、了解系统调用pipe()、msgget()、msgsnd()、msgrcv ()、msgctl()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。 2、编写一段程序,使其用管道来实现父子进程之间的进程通讯。子进程向父进程发送自己的进程标识符,以及字符串“is sending a message to parent!”。父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。 3、编写一段程序,使用系统调用fork()来创建两个子进程CLIENT进程和SERVER进程,使其用消息缓冲队列来实现CLIENT进程和SERVER进程之间的通信。SERVER端建立一个Key为75的消息队列,等待其他进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER。SERVER每接收到一条消息后显示一句“(server) received”。CLIENT端使用Key为75的消息队列,先后发送类型从10到1的消息,然后退出。最后的一个消息,即是SERVER端需要的结束信号。CLIENT每发送一条消息后显示一句“(client) sent”。父进程在SERVER和CLIENT均退出后结束。 4、编写一个与3具有类似功能的程序,使其用共享存储区来实现两个进程之间的通讯。 【主要仪器设备】 每人一台计算机,硬件要求:CPU PII以上,64M内存,1OOM硬盘空间即可;软件要求: Linux操作系统。
进程间通信方式比较
进程间的通信方式: 1.管道(pipe)及有名管道(named pipe): 管道可用于具有亲缘关系进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 2.信号(signal): 信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致得。 3.消息队列(message queue): 消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息。 消息缓冲通信技术是由Hansen首先提出的,其基本思想是:根据”生产者-消费者”原理,利用内存中公用消息缓冲区实现进程之间的信息交换. 内存中开辟了若干消息缓冲区,用以存放消息.每当一个进程向另一个进程发送消息时,便申请一个消息缓冲区,并把已准备好的消息送到缓冲区,然后把该消息缓冲区插入到接收进程的消息队列中,最后通知接收进程.接收进程收到发送里程发来的通知后,从本进程的消息队列中摘下一消息缓冲区,取出所需的信息,然后把消息缓冲区不定期给系统.系统负责管理公用消息缓冲区以及消息的传递. 一个进程可以给若干个进程发送消息,反之,一个进程可以接收不同进程发来的消息.显然,进程中关于消息队列的操作是临界区.当发送进程正往接收进程的消息队列中添加一条消息时,接收进程不能同时从该消息队列中到出消息:反之也一样. 消息缓冲区通信机制包含以下列内容:
(1) 消息缓冲区,这是一个由以下几项组成的数据结构: 1、消息长度 2、消息正文 3、发送者 4、消息队列指针 (2)消息队列首指针m-q,一般保存在PCB中。 (1)互斥信号量m-mutex,初值为1,用于互斥访问消息队列,在PCB中设置。 (2)同步信号量m-syn,初值为0,用于消息计数,在PCB中设置。(3)发送消息原语send (4)接收消息原语receive(a) 4.共享内存(shared memory): 可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。 这种通信模式需要解决两个问题:第一个问题是怎样提供共享内存;第二个是公共内存的互斥关系则是程序开发人员的责任。 5.信号量(semaphore): 主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段。 6.套接字(socket); 这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。 https://www.360docs.net/doc/0e7486536.html,/eroswang/archive/2007/09/04/1772350.aspx linux下的进程间通信-详解
进程间的通信
# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 # 有名管道(named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 # 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 # 消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 # 信号( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。 # 套接字( socket ) :套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 windows进程通信的几种方式(转) 2008-10-13 16:47 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容。 Win32 API允许多个进程访问同一文件映射对象,各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针,不同进程就可以读或修改文件的内容,实现了对文件中数据的共享。 应用程序有三种方法来使多个进程共享一个文件映射对象。 (1)继承:第一个进程建立文件映射对象,它的子进程继承该对象的句柄。 (2)命名文件映射:第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外,第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。 (3)句柄复制:第一个进程建立文件映射对象,然后通过其它IPC机制(有名管道、邮件槽等)把对象句柄传递给第二个进程。第二个进程复制该句柄就取得对该文件映射对象的访问权限。 文件映射是在多个进程间共享数据的非常有效方法,有较好的安全性。但文件映射只能用于本地机器的进程之间,不能用于网络中,而开发者还必须控制进程间的同步。 2 共享内存 Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊情况。进程在创建文件映射对象时用0xFFFFFFFF来代替文件句柄(HANDLE),就表示了对应的文件映射对象是从操作系统页面文件访问内存,其它进程打开该文件映射