Unix进程与进程通信
- 格式:doc
- 大小:255.50 KB
- 文档页数:64
pipe()函数介绍pipe()函数是Unix/Linux系统中一种IPC(Inter-process Communication,进程间通信)机制,用于创建一个管道(Pipe),实现父进程和子进程之间的数据通信。
管道被认为是进程间通信的最简单形式,通常被用于进程之间的数据传输和同步。
管道管道是一种半双工的数据通信方式,也就是说,同一时刻,它只能实现数据的单向传输,一端写入数据,另一端可以读出数据,但是不能同时读写数据。
管道被创建时,系统会在内存中分配一段缓冲区,用于存储数据的传输,它通常被称为“管道”,这样就可以实现进程之间的数据通信。
在Linux的文件系统中,管道被对应为一种特殊的文件类型,命名为“管道文件”,也可以被表示为“|”。
在UNIX环境下,管道是通过fork()和exec()系统调用创建的。
在C语言中,创建管道的函数是pipe(),该函数的原型如下:```cint pipe(int pipefd[2]);```该函数传递一个整型数组,用于存储两个文件描述符,分别表示管道的读端和写端。
在成功创建管道后,pipe()函数返回0,否则返回-1,表示创建管道失败。
管道的读端用于从管道中读取数据,写端用于将数据写入管道。
当读取端口被关闭时,表示管道的末端已经被关闭,写入到管道的数据在读取端口被读取后不再可用。
父进程和管道通信下面是一个简单的父子进程通信的例子。
父进程会从标准输入中读取数据,并将数据写入到管道中。
然后子进程从管道中读取数据,并将数据打印到标准输出中。
该例子中,父子进程之间使用管道进行数据通信。
```c#include <stdio.h>#include <unistd.h>#include <string.h>#define BUFSIZE 256/* 创建管道 */if (pipe(fd) < 0) {perror("pipe");return -1;}if (pid == 0) { // 子进程close(fd[1]); // 子进程关闭写端口int n = read(fd[0], buf, BUFSIZE);/* 读取父进程写入管道中的数据 */write(STDOUT_FILENO, buf, n);write(STDOUT_FILENO, "\n", 1);close(fd[0]);} else { // 父进程close(fd[0]); // 父进程关闭读端口/* 从标准输入中读取数据 */int n = read(STDIN_FILENO, buf, BUFSIZE); /* 将读取的数据写入管道 */write(fd[1], buf, n);close(fd[1]);}return 0;}```在该程序中,父进程使用write()函数向管道中写入数据,子进程使用read()函数从管道中读取数据。
system v进程间通信原理
System V进程间通信原理指的是在Unix-like操作系统中,通过System V的机制进行进程间通信的原理。
System V提供了三种主要的进程间通信方式:消息队列、信号量和共享内存。
1. 消息队列:进程通过将消息发送到消息队列中,然后其他进程可以从队列中接收这些消息。
消息队列是一种先进先出的数据结构,确保消息的有序传递。
发送和接收进程必须使用特定的标识符来访问消息队列。
2. 信号量:信号量是一个计数器,用于控制多个进程对共享资源的访问。
进程可以对信号量进行P(通过资源)和V(释放资源)操作。
当一个进程需要访问共享资源时,它先进行一次P操作,如果信号量大于0,则允许进程访问资源,然后进程对信号量进行一次V操作来释放资源。
如果信号量等于0,则进程必须等待,直到信号量大于0。
3. 共享内存:共享内存是一块被多个进程共享的内存区域。
多个进程可以将共享内存映射到它们自己的地址空间中,并可以直接访问这些共享内存。
共享内存的读取和写入速度较快,但需要确保多个进程之间对共享内存的访问是同步和互斥的,以避免数据不一致的问题。
System V进程间通信原理的核心思想是通过一系列的系统调
用来实现进程间的信息传递和资源共享,从而实现进程之间的协作和同步。
操作系统中的信号机制信号机制是操作系统的一个重要特性,通过它,应用程序可以与操作系统进行通信,实现进程间的协调和同步。
在本文中,将详细介绍信号机制的原理、使用和实现方法,并探讨其在操作系统中应用的重要性和作用。
一、信号机制的原理信号机制的原理是在操作系统中,某个进程通过向另一个进程发送信号,来通知这个进程某些事情已发生。
在Linux和Unix系统中,每个进程都有一个唯一的进程ID,通过信号,进程可以向目标进程发送指定的信号号码,目标进程将收到这个信号,并对其进行处理。
信号可以分为两种类型:软件中断和硬件中断。
软件中断是由操作系统中断处理程序发出的,用于通知应用程序某个事件已经发生;硬件中断是由系统硬件设备发出的,例如鼠标或键盘按键、定时器等。
在Unix系统中,每个信号都有一个唯一的编号,通常在1~31之间。
其中,0号信号表示检查进程是否存在,1号信号表示终止进程,2号信号表示中断进程执行等等。
除此之外,还有一些用户自定义的信号,可以用于特定的应用程序场景。
二、信号机制的使用在Linux和Unix系统中,可以使用kill命令发送信号。
该命令的基本语法是:kill [-s ]。
其中,表示需要发送的信号号码,可以是从1开始的任意整数;表示需要发送信号的进程ID。
如果没有指定信号号码,默认发送15号信号,即终止进程。
除了kill命令,应用程序也可以使用系统调用函数来发送信号。
例如,使用kill函数和raise函数可以向指定的进程ID或当前进程发送信号,如下所示:#include <sys/types.h>#include <sys/signal.h>int kill(pid_t pid, int sig);int raise(int sig);在应用程序中,通常会使用信号处理函数来定义信号的处理方式。
应用程序使用signal函数注册信号处理函数,并在信号发生时执行预先定义好的操作。
进程间通信的⼏种⽅式典型回答1. 套接字套接字为通信的端点。
通过⽹络通信的每对进程需要使⽤⼀对套接字,即每个进程各有⼀个。
每个套接字由⼀个 IP 地址和⼀个端⼝号组成。
通常,套接字采⽤ CS 架构,服务器通过监听指定的端⼝,来等待特定服务。
服务器在收到请求后,接受来⾃客户端套接字的连接,从⽽完成连接。
2. 管道管道提供了⼀个相对简单的进程间的相互通信,普通管道允许⽗进程和⼦进程之间的通信,⽽命名管道允许不相关进程之间的通信。
知识延伸进程间通信有两种基本模型:共享内存和消息传递。
共享内存模型会建⽴起⼀块供协作进程共享的内存区域,进程通过向此共享区域读出或写⼊数据来交换信息。
消息传递模型通过在协作进程间交换信息来实现通信。
下图给出了两个模型的对⽐:很多系统同时实现了这两种模型。
消息传递对于交换较少数量的数据很有⽤,因为⽆需避免冲突。
对于分布式系统,消息传递也⽐共享内存更易实现。
共享内存可以快于消息传递,这是因为消息传递的实现经常采⽤系统调⽤,因此需要更多的时间以便内核介⼊。
与此相反,共享内存系统仅在建⽴共享内存区域时需要系统调⽤;⼀旦建⽴共享内存,所有访问都可作为常规内存访问,⽆需借助内核。
对具有多个处理核的系统上,消息传递的性能要优于共享内存。
共享内存会有⾼速缓存⼀致性问题,这是由共享数据在多个⾼速缓存之间迁移⽽引起的。
随着系统处理核的⽇益增加,可能导致消息传递作为 IPC 的⾸选机制。
共享内存系统采⽤共享内存的进程间通信,需要通信进程建⽴共享内存区域。
通常,这⼀⽚共享内存区域驻留在创建共享内存段的进程地址空间内。
其它希望使⽤这个共享内存段进⾏通信的进程应将其附加到⾃⼰的地址空间。
回忆⼀下,通常操作系统试图阻⽌⼀个进程访问另⼀个进程的内存。
共享内存需要两个或更多的进程同意取消这⼀限制;这样它们通过在共享区域内读出或写⼊来交换信息。
数据的类型或位置取决于这些进程,⽽不是受控于操作系统。
另外,进程负责确保,它们不向同⼀位置同时写⼊数据。
实验报告实验题目姓名:学号:课程名称:操作系统实验所在学院:信息科学与工程学院专业班级:计算机任课教师:实验项目名称进程通信——共享存储区和信号量一、实验目的与要求:1、了解和熟悉共享存储机制2、了解和熟悉信号量机制3、熟悉信号量机制中使用的数据结构和信号量机制的操作以及控制。
4、了解共享主存段机制,学会对共享主存段的系统调用。
二、实验设备及软件:1、PC机一台2、Linux操作系统三、实验方法(原理、流程图)一、共享存储区1、共享存储区机制的概念共享存储区(Share Memory)是 UNIX 系统中通信速度最高的一种通信机制。
该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。
另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。
当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。
此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。
进程之间便可通过对共享存储区中数据的读、写来进行直接通信。
图示列出二个进程通过共享一个共享存储区来进行通信的例子。
其中,进程 A 将建立的共享存储区附接到自己的 AA’区域,进程 B 将它附接到自己的 BB’区域。
应当指出,共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。
因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。
二、涉及的系统调用1、shmget( )创建、获得一个共享存储区。
系统调用格式: shmid=shmget(key,size,flag)参数定义: int shmget(key,size,flag);key_t key;int size,flag;其中,key是共享存储区的名字;size是其大小(以字节计);flag是用户设置的标志,如IPC_CREAT。
UNIX系统开发-系统调用-进程间高级通信基本上所有的系统调用成功时返回0或正数,失败时返回负值。
消息通信每个消息队列都有一个msqid_ds类型的控制结构,该结构中包括对消息队列的访问权限,其数据结构如下:struct msqid_ds{struct ipc_perm msg_perm; /*操作权限结构*/struct msg msg_first; /*指向消息队列的第一个结构*/struct msg msg_last; /*指向消息队列的最后一个结构*/ushort msg_cbytes; /*队列中当前字节数*/ushort msg_qnum; /*队列中消息数*/ushort msg_qbytes; /*队列可容纳的最大字节数*/ushort msg_lspid; /*最后发送消息的进程号*/ushort msg_lrpid; /*最后接收消息的进程号*/ushort msg_stime; /*最后发送时间*/ushort msg_rtime; /*最后接收时间*/time_t msg_ctime; /*消息队列最后修改时间*/};msgget系统调用的格式#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key,msgflg)key_t key; /*消息队列关键字*/int msgflags; /*创建标志和访问方式(类似于文件访问权限)*/参数与功能说明:msgflg低9位类似于文件访问权限的低9位,其他位指明消息队列的建立方式:若指定的关键字消息队列不存在,msgflg&IPC_CREAT为真,则为他建立一个新的消息队列;msgflg&IPC_CREAT为假,返回-1。
若指定的关键字消息队列存在,则返回该消息队列的描述符。
若msgflg&IPC_CREAT&IPC_EXCL为真,若指定的关键字消息队列不存在,失败返回-1;否则正常返回。
Unix进程与进程通信讲稿Version 1.0Unix Process&IPC达内IT培训集团修订历史摘要日期修改原因版本文档创建2009-4-18 新建 1.0目录1.理解进程 (7)1.1.进程的基本概念 (7)1.1.1.区别程序与进程 (7)1.1.2.进程分类 (7)1.1.3.进程属性 (7)1.1.4. 父进程和子进程 (7)1.2.Unix/Linux下的进程管理 (8)1.2.1.进程是系统资源管理的基本单位 (8)1.2.2. Unix/Linux进程 (8)1.2.3. task_struct数据结构组成 (9)1.2.4.进程Identifiers (10)1.2.6. 进程创建 (12)1.2.7.Unix/Linux进程管理工具 (13)2.进程编码 (16)2.1.fork函数的使用 (16)2.1.1.fork函数说明 (16)2.1.2.创建进程 (16)2.1.3.理解子进程 (17)2.1.3.1.子进程继承父进程: (17)2.1.3.2.子进程与父进程的关系 (17)2.1.3.3.孤儿子进程 (17)2.1.3.4.僵尸子进程 (17)2.2.wait函数的使用 (18)2.2.1.wait函数说明 (18)2.2.2.使用wait处理僵尸进程 (18)2.3.进程中简单信号的使用 (19)2.3.1.理解信号 (19)2.3.1.1.信号的本质 (19)2.3.1.2.信号来源 (19)2.3.2.简单的发送信号的函数 (20)2.3.2.1.sleep函数 (20)2.3.2.2.abort函数 (20)2.3.2.3.exit函数 (20)2.3.3.信号发送示例 (20)2.4.其他进程函数 (21)2.4.1.getpid函数 (21)2.4.2.getppid函数 (21)2.4.3.system函数 (22)2.4.4.execl函数系列 (22)2.4.5.popen函数 (23)3. 信号 (25)3.1.信号种类 (25)3.1.1.可靠信号与不可靠信号 (25)3.1.1.1.不可靠信号 (25)3.1.1.2.可靠信号 (25)3.1.2.实时信号与非实时信号 (26)3.2.常用信号 (26)3.3.信号发送 (27)3.3.1.kill函数说明 (27)3.3.2.raise函数说明 (27)3.3.3.sigqueue函数说明 (27)3.3.4.alarm函数说明 (28)3.3.5.setitimer函数说明 (28)3.3.6.abort函数说明 (29)3.4.信号的响应 (29)3.5. 信号的安装 (29)3.5.1. signal函数说明 (30)3.5.2. sigaction函数说明 (30)3.5.2.1.sigaction结构体定义 (31)3.5.2.2. sigaction结构体数据说明 (31)3.6.信号操作 (32)3.6.1.信号操作函数说明 (32)3.7.信号处理示例 (33)3.7.1.使用信号处理僵尸进程 (33)3.7.2.alarm定时器与setitimer定时器 (34)3.7.3.使用kill与raise发送信号 (36)3.7.4.各种信号的使用 (37)3.7.5.sigaction的使用 (39)3.8.信号的阻塞 (41)4. 进程间通信 (43)4.1.匿名管道 (43)4.1.1.匿名管道函数说明 (43)4.1.2.匿名管道编程步骤 (44)4.1.3.匿名管道代码示例 (45)4.2.有名管道 (46)4.2.1.有名管道函数说明 (46)4.2.2.有名管道编程步骤 (47)4.2.3.有名管道代码示例 (47)4.3.内存映射 (49)4.3.1.内存映射函数说明 (49)4.3.2.内存映射编程步骤 (50)4.3.3.内存映射代码示例 (50)4.4.共享内存 (52)4.4.1.共享内存函数说明 (52)4.4.2.共享内存编程步骤 (53)4.4.3.共享内存代码示例 (53)4.5.消息队列 (55)4.5.1.消息队列函数说明 (55)4.5.2.消息队列编程步骤 (56)4.5.3.消息队列代码示例 (56)4.6.信号量 (59)4.6.1.信号量函数说明 (59)4.6.2.信号量编程步骤 (60)4.6.3.信号量代码示例 (61)1.理解进程1.1.进程的基本概念1.1.1.区别程序与进程进程就是运行中的程序。
一个运行着的程序,可能有多个进程。
进程在操作系统中执行特定的任务。
程序是存储在磁盘上包含可执行机器指令和数据的静态实体。
进程或者任务是处于活动状态的计算机程序。
1.1.2.进程分类进程一般分为交互进程、批处理进程和守护进程三类。
值得一提的是守护进程总是活跃的,一般是后台运行,守护进程一般是由系统在开机时通过脚本自动激活启动或超级管理用户root来启动。
1.1.3.进程属性1.进程ID(PID):是唯一的数值,用来区分进程;2.父进程和父进程的ID(PPID);3.启动进程的用户ID(UID)和所归属的组(GID);4.进程状态:状态分为运行R、休眠S、僵尸Z;5.进程执行的优先级;6.进程所连接的终端名;7.进程资源占用:比如占用资源大小(内存、CPU占用量);1.1.4. 父进程和子进程他们的关系是产生的依赖关系,当父进程终止时,子进程也随之而终止(某些情况下例外,在第二部分进程编程中可以看到这点)。
但子进程终止,父进程并不一定终止。
1.2.Unix/Linux下的进程管理1.2.1.进程是系统资源管理的基本单位进程是一个随执行过程不断变化的实体。
和程序要包含指令和数据一样,进程也包含程序计数器和所有CPU寄存器的值,同时它的堆栈中存储着如子程序参数、返回地址以及变量之类的临时数据。
当前的执行程序,或者说进程,包含着当前处理器中的活动状态。
Linux是一个多处理操作系统。
进程具有独立的权限与职责。
如果系统中某个进程崩溃,它不会影响到其余的进程。
每个进程运行在其各自的虚拟地址空间中,通过核心控制下可靠的通讯机制,它们之间才能发生联系。
进程在生命期内将使用系统中的资源。
它利用系统中的CPU来执行指令,在物理内存来放置指令和数据。
使用文件系统提供的功能打开并使用文件,同时直接或者间接的使用物理设备。
Linux必须跟踪系统中每个进程以及资源,以便在进程间实现资源的公平分配。
如果系统有一个进程独占了大部分物理内存或者CPU的使用时间,这种情况对系统中的其它进程是不公平的。
系统中最宝贵的资源是CPU,通常系统中只有一个CPU。
Linux是一个多处理操作系统,它最终的目的是:任何时刻系统中的每个CPU上都有任务执行,从而提高CPU的利用率。
如果进程个数多于CPU的个数,则有些进程必须等待到CPU空闲时才可以运行。
多处理是的思路很简单;当进程需要某个系统资源时它将停止执行并等待到资源可用时才继续运行。
单处理系统中,如DOS,此时CPU将处于空等状态,这个时间将被浪费掉。
在多处理系统中,因为可以同时存在多个进程,所以当某个进程开始等待时,操作系统将把CPU 控制权拿过来并交给其它可以运行的进程。
调度器负责选择适当的进程来运行,Linux使用一些调度策略以保证CPU分配的公平性。
1.2.2. Unix/Linux进程为了让Unix/Linux来管理系统中的进程,每个进程用一个task_struct数据结构来表示(任务与进程在Unix/Linux中可以混用)。
数组task包含指向系统中所有task_struct结构的指针。
这意味着系统中的最大进程数目受task数组大小的限制,缺省值一般为512。
创建新进程时,Unix/Linux将从系统内存中分配一个task_struct结构并将其加入task数组。
当前运行进程的结构用current指针来指示。
Unix/Linux还支持实时进程。
这些进程必须对外部时间作出快速反应(这就是“实时”的意思),系统将区分对待这些进程和其他进程。
1.2.3. task_struct数据结构组成1.State进程在执行过程中会根据环境来改变state。
Unix/Linux进程有以下状态:2.Running进程处于运行(它是系统的当前进程)或者准备运行状态(它在等待系统将CPU分配给它)。
3.Waiting进程在等待一个事件或者资源。
Linux将等待进程分成两类;可中断与不可中断。
可中断等待进程可以被信号中断;不可中断等待进程直接在硬件条件等待,并且任何情况下都不可中断。
4.Stopped进程被停止,通常是通过接收一个信号。
正在被调试的进程可能处于停止状态。
5.Zombie这是由于某些原因被终止的进程,但是在task数据中仍然保留task_struct结构。
它象一个已经死亡的进程。
6.Scheduling Information调度器需要这些信息以便判定系统中哪个进程最迫切需要运行。
7.Identifiers系统中每个进程都有进程标志。
进程标志并不是task数组的索引,它仅仅是个数字。
每个进程还有一个用户与组标志,它们用来控制进程对系统中文件和设备的存取权限。
8.Inter-Process CommunicationUnix/Linux支持经典的Unix IPC机制,如信号、管道和信号灯以及系统V中IPC机制,包括共享内存、信号灯和消息队列。
9.LinksUnix/Linux系统中所有进程都是相互联系的。
除了初始化进程外,所有进程都有一个父进程。
新进程不是被创建,而是被复制,或者从以前的进程克隆而来。
每个进程对应的task_struct结构中包含有指向其父进程和兄弟进程(具有相同父进程的进程)以及子进程的指针。
以使用pstree命令来观察Unix/Linux系统中运行进程间的关系。
(Solaris的指令是ptree)另外,系统中所有进程都用一个双向链表连接起来,而它们的根是init进程的task_struct数据结构。
这个链表被Unix/Linux核心用来寻找系统中所有进程,它对ps或者kill命令提供了支持。
10.Times and Timers核心需要记录进程的创建时间以及在其生命期中消耗的CPU时间。
时钟每跳动一次,核心就要更新保存在jiffies变量中,记录进程在系统和用户模式下消耗的时间量。
Linux支持与进程相关的interval定时器,进程可以通过系统调用来设定定时器以便在定时器到时后向它发送信号。
这些定时器可以是一次性的或者周期性的。
11.File system进程可以自由地打开或关闭文件,进程的task_struct结构中包含一个指向每个打开文件描叙符的指针以及指向两个VFS inode的指针。