Linux进程控制及进程间通信

实验目的

熟悉Linux进程控制编程,掌握多进程程序中相关函数的作用,理解Linux中多进程编程的步骤;熟悉进程间通信中管道的使用。

实验内容

熟悉Linux进程控制编程;
熟悉Linux进程间通信的6种方式;
掌握Linux进程有关的函数调用。

实验准备

  熟悉Linux常用命令以及ubuntu终端操作方法;
  熟悉vim等工具的安装和使用;
  熟悉gcc编译及make和makefiel机制。

实验内容

理解fork、exec函数族、exit、_exit、wait、waitpid、setsid、chdir、umask、getdtablesize等函数的应用

execlp函数:execlp()函数属于exec()函数族,exec()族函数用一个新的进程映像替换当前进程映像。

execl函数:execl()其中后缀"l"代表list也就是参数列表的意思,第一参数path字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]… 最后一个参数须用空指针NULL作结束。

execle函数:将新程序的每个命令行参数都说明为 一个单独的参数。这种参数表以空指针结尾。


execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用数组指针来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。

exit函数将终止调用进程。在退出程序之前,所有文件关闭,缓冲输出内容将刷新定义:


_exit:该函数是由Posix定义的,不会运行exit handler和signal handler,在UNIX系统中不会flush标准I/O流。
简单的说,_exit终止调用进程,但不关闭文件,不清除输出缓存,也不调用出口函数。
exit()与_exit()的共同点:
不管进程是如何终止的,内核都会关闭进程打开的所有file descriptors,释放进程使用的memory。

waitpid()函数:
waitpid()函数在linux中的原型为:
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid,int *status,int options)

从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式
pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
 WNOHANG => waitpid将不阻塞如果指定的pid并未结束
 WUNTRACED => 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。


syslog_daemon:记录至系统记录的守护进程程序:

setsid()函数:让函数在终端关闭后依旧在后台运行。
setsid [options] program [arguments]

chdir函数:chdir函数用于改变当前工作目录。调用参数是指向目录的指针,调用进程需要有搜索整个目录的权限。

umask函数:主要用于设置允许当前进程创建文件或者目录最大可操作的权限。
在创建新文件或目录时 屏蔽掉新文件或目录不应有的访问允许权限。文件的访问允许权限共有9种,分别是:r w x r w x r w x(它们分别代表:用户读 用户写 用户执行 组读 组写 组执行 其它读 其它写 其它执行)。

gettablesize()函数:用来返回这个进程的文件描述表的项数,也就是说这个进程所打开的文件的数目。// Get the size of the file descriptor table

分析有关多进程应用的代码,掌握多个子进程的执行竞争关系。

multi_proc函数:multi_proc函数表现了子进程的竞争。首先利用fork函数分叉出第一个子进程1,如果分叉成功则让子进程1执行execlp函数(当前status下的进程映像)。如果fork函数出错未能分叉出子进程1,则我们选择继续分叉另外一个进程,也就是子进程2。如果子进程2分叉失败,则直接调用exit()函数退出。如果子进程分叉成功则让其休眠5 secs。然后调用waitpid()函数来阻塞child1,如果child1已经结束则阻塞它,把进程号返回给child,此时打印"get child1 exit code"。使用do while结构一直查询child2是否已经结束,一旦结束waitpid()便阻塞它并返回它的pid,打印“get child2 exit code”。


分析有关管道的例子代码,理解pipe、popen、pclose、mkfifo、access等函数的应用
pipe函数:
管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次
都需要提供两个文件描述符来操作管道。其中一个对管道进行写操作,另一个对管道进行读操作。

该函数创建了两个进程,父进程用于读操作,子进程用于写操作。创建了一个管道,再fork了一个子进程,if对于子进程,先让子进程关闭了写fd再让父进程关闭读fd,接着让子进程读取管道内容并打印出来读取的管道内容长度,关闭子进程读fd。else对于父进程,父进程关闭读fd然后让子进程关闭相应的写fd,父进程向管道中写入字符串,并打印出来写了多少字节。最后关闭父进程的写fd,并用waitpid()阻塞子进程,收集子进程的退出信息。


Popen函数:popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。
参数type可使用“r”代表读取,“w”代表写入。
依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。
随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中


Pclose()函数:函数功能:pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针
返回值:若成功返回shell的终止状态(也即子进程的终止状态),若出错返回-1,错误原因存于errno中
Mkfifo()函数:
命名管道(FIFO)

匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。

mkfifo是一个建立实名管道的函数。


分析有关信号的例子代码,理解kill、raise、alarm、pause、signal、sigaction、sigemptyset、sigfillset、sigaddset、sigismember、sigdelset、sigprocmask、sigpending等函数的应用。

用raise()函数发送sigstop信号,使子进程暂停。Kill()函数接受到信号以后进行相应的操作。

Alarm函数:
alarm()函数的主要功能是设置信号传送闹钟,即用来设置信号SIGALRM在经过参数seconds秒数后发送给目前的进程。如果未设置信号SIGALARM的处理函数,那么alarm()默认处理终止进程。


Signal函数:
自定义信号处理函数,根据主程序接收到的输入来判定SIGINT或者SIGQUIT。


Sigaction函数:sigaction函数的功能是检查或修改与指定信号相关联的处理动作(或同时执行这两种操作)。

Sigset函数:信号集及信号集操作函数:信号集被定义为一种数据类型。

sigemptyset:初始化信号集合为空。
sigfillset:把所有信号加入到集合中,信号集中将包含Linux支持的64种信号。
sigaddset:将指定信号加入到信号集合中去。
sigdelset:将指定信号从信号集中删去。
sigismember:查询指定信号是否在信号集合之中。

分析有关管道应用的代码,掌握有名管道的多路通信方式。

有名管道和无名管道基本相同,但也有不同点:无名管道只能由父子进程使用;但是通过有名管道,不相关的进程也能通信和交换数据。


多路通信步骤:
新建终端1和终端2:



执行pipe_select函数:


可以看到我们已经成功建立了管道,进行了通信。

全部评论

相关推荐

点赞 1 评论
分享
牛客网
牛客企业服务