收藏 分享(赏)

Unix程序设计基础第三讲.ppt

上传人:11xg27ws 文档编号:8693816 上传时间:2019-07-07 格式:PPT 页数:34 大小:87KB
下载 相关 举报
Unix程序设计基础第三讲.ppt_第1页
第1页 / 共34页
Unix程序设计基础第三讲.ppt_第2页
第2页 / 共34页
Unix程序设计基础第三讲.ppt_第3页
第3页 / 共34页
Unix程序设计基础第三讲.ppt_第4页
第4页 / 共34页
Unix程序设计基础第三讲.ppt_第5页
第5页 / 共34页
点击查看更多>>
资源描述

1、Unix程序设计基础 第三讲,谢翰 2004-2-10,Reviews of last class,进程 独立地址空间的指令序列 五种状态基本状态:新建,就绪,运行,睡眠,僵死 状态转换图 进程ID,子进程,父进程 Unix下的多进程编程 fork与execve:进程的创建与程序的运行 wait,waitpid:回收子进程的退出状态,Reviews of last class,信号 是Unix操作系统用来通知进程发生了某种事件的一种手段。也称为软件中断 几个常用的信号 信号编程 signal与sigaction:改变信号动作 alarm:设置闹钟 不可重入函数: 在函数返回之前不可再次被调用,

2、如printf,malloc。,信号编程(续),功能更强的改变信号动作函数:sigaction。 解决早期signal函数的不可靠问题:在信号处理过程中再次收到这个信号怎么办? 一般情况下用不到,请自己看书。 发送信号函数kill与raise。 函数原型: #include int kill(pid_t pid, int sig); int raise(int sig);,信号的发送,kill给进程号为pid的进程发送一个sig信号 pid 0:发送给进程ID为pid的进程 pid = 0:发送给与自己同组,并且自己有权限向其发送的进程 pid -1:发送给进程组ID为-pid的进程,并且自己

3、有权限向其发送的进程 pid = -1:所有自己有权限向其发送信号的进程,信号的发送,raise调用给自己发关一个sig信号。因此,raise(sig);等价于kill(getpid(), sig); 发送信号的shell命令:kill。 在默认情况下发送的是SIGTERM信号 $ kill 12345 等价于 $ kill TERM 12345,都是向进程12345发送一个SIGTERM信号。 $ kill KILL 12345,向进程12345发送一个SIGKILL信号,信号的屏蔽,在一段时间内屏蔽掉某些信号,让当前进程接收不到这些信号。 与忽略信号(remember?)不同,被屏蔽的信号

4、会被保存起来(但不排队),在屏蔽解除后会被进程收到。 注意一点:一般情况下用signal函数设置信号动作,在某信号处理过程中,该信号是被屏蔽的。,实例:SIGCHLD信号,不详细讲关于信号屏蔽的系统调用,因为不是很重要,而且内容太多。但我想通过一个例子来让大家了解信号屏蔽:某个进程通过调用fork创建多个子进程:for (i = 0; i n; i+) if (pid = fork() = 0)break;,实例:SIGCHLD信号,当父进程给束之前,必须调用wait来回收子进程的退出状态,如:for (i = 0; i n; i+)wait( 但这就存在一个问题:只有当父进程结束子进程的状态

5、才能被回收,子进程占用的进程表项才可以被释放。能不能子进程一结束就把它回收?,实例:SIGCHLD信号,回顾上一结,有一个信号叫做SIGCHLD,当子进程停止或结束,父进程将收到一个SIGCHLD信号,默认动作是忽略。 我们自然会想到在SIGCHLD信号的处理函数中调用wait。于是:void sig_chld(int signo) int status;wait(,实例:SIGCHLD信号,当然我们还要设置SIGCHLD的处理函数:signal(SIGCHLD, sig_chld); 好像已经大功告成,但实际上却存在问题。 (程序演示) 我们看到,系统中留下了很多僵死的进程,说明它们的退出状

6、态并没有被回收,这是为什么?,实例:SIGCHLD信号,解答: 前面说到,在信号处理过程中,相同的信号是被屏蔽的。也就是说,在sig_chld过程中进程是不会再收到SIGCHLD信号的。 被屏蔽的信号被保存下来,在sig_chld返回之后进程会收到被屏蔽的信号。 但是,被屏蔽信号的保存是不排队的,也就是说,进程知道在信号屏蔽过程中有没有收到这个信号,而无法知道收到几个。,实例:SIGCHLD信号,结果:父进程只回收到了某些子进程的退出状态。 解决办法:这样子改写sig_chld函数:void sig_chld(int signo) int status;while (waitpid(-1, ,

7、进程间通信(IPC),著名Unix与网络专家Richard Stevens,有多本Unix著作,本本经典。 Advanced Programming In the Unix Environment (APUE) TCP/IP Illustrated volume 1, 2, 3 Unix Network Programming (UNP) volume 1, 2 1999年9月30号去世TT,UNP volume 3没有写完。,进程间通信(IPC),UNP volume 2:用了一本书来讲IPC 所以,我不可能在半节课之内涵盖IPC的各个方面,只能讲一些最基本,也是最重要的: 管道通信 FIF

8、O通信,管道通信,最古老的Unix IPC工具,一个进程从管道一头写数据,另一个进程从管道另一头读数据。相通信方式是单向的。 (演示shell下的管道通信) 先了解一下进程创建过程中文件描述字的继承。,单个进程打开两个文件,fork之后,管道通信,创建管道pipe 函数原型: #include int pipe(int fdes2);pipe函数成功后,内核打开两个文件描述字fdes0,fdes1。fdes0输入端,fdes1为输出端。,当进程调用了pipe,fork被调用后,两个进程分别关闭一个端,int main(void) pid_t pid;int fdes2;if (pipe(fde

9、s) 0) close(fdes0);write(fdes1, “Hmmmmmmmmmmm”, 12);/* 1 2 3 4 5 6 7 8 9 0 1 2 */else char buf4096; ssize_t n;close(fdes1)n = read(fdes0, buf, 4096);if (n = 0) bufn = 0; printf(“%sn”, buf); return 0; ,管道破裂,如果一个管道的读端已经关闭,进程还继续向写端写数据,如:pipe(fdes);close(fdes0);write(fdes1, “Let me die”, 10);则进程会收到一个SIG

10、PIPE信号,表示管道破裂。默认动作为结束进程。 读一个写端已经关闭的管道则read返回0。,FIFO通信,FIFO是一种特殊设备文件,又称为有名管道。操作方法与普通文件相同。 对于普通文件,我们可以从文件任一位置读数据,也可以从任一位置写数据;数据读完不会消失。但对FIFO来说,我们只能从文件头读数据,从文件尾写数据。数据被某进程读走之后就会消失。 (实例演示),FIFO相关的调用和shell命令,创建设备文件FIFO:mkfifo函数原型:#include #include int mkfifo(const char *filename,mode_t mode); shell命令:$ mk

11、fifo m 0600 fifo1,线程简介,Linux下的clone系统调用可以实现比fork更多的功能,比如让创建出来的子进程分享父进程的地址空间。 习惯上把这些与父进程分享地址空间的子进程称为线程(Thread)。 不同的系统对线程有不一样的定义,但相同之处是它比进程的开消小,因此也被称为是轻量级进程。,线程简介,因为地址空间共享使得线程之间的通信非常方便,但必须特别注意数据一致性。 Posix定了标准的线程接口,请参考UNP volume 1,Chapter 23,高级IO,I/O的方式有很多种,我们之前使用的IO方式的特点是: 单路:只能等待一个fd可读或可写 阻塞:睡眠直到fd可读

12、或可写 同步:read和write必须结束才返回? 因此有与之对应的: 多路:同时等待多个fd可读或可写 非阻塞:fd不可读或不可写立即返回 异步:I/O没有结束read和write也可返回,非阻塞I/O,以非阻塞方式打开一个文件,如:fd = open(“love.txt”, O_RDWR | O_NONBLOCK, 0); 也可以用fcntl让一个已经打开的文件描述字变成非阻塞:flags = fcntl(fd, F_GETFL, 0);fcntl(fd, F_SETFL, flags | O_NONBLOCK);,非阻塞I/O,对一个非阻塞的fd来说,如果它无数据可读,则read(fd,

13、 );返回-1,errno的值被置为EAGAIN;同样,如果它暂时不可写,write(fd, );返回-1,errno=EAGAIN。(阻塞式I/O在这两种情况下都是等待)。 注意:应当区为无数据可读与文件已经读到结尾。后者read返回0,无论阻塞否。 非阻塞I/O经常与多路I/O配合使用。,多路I/O,想像一个fd集合fdset,以及一个函数fun,我们指定:调用fun(fdset)进程进入睡眠,直到fdset中至少有一个fd可读,此时fun返回并把可读的fd保存在fdset中。 这样做的好处是,我们可以同时从多个fd中等待数据,如果某一个可读我们就从中读取,否则就睡眠。,多路I/O,Unix下就存在这种的一个fun,但它的功能更加强大。它就是select(在有的系统下为poll,Linux都支持)函数原型: #include #include int select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout);,多路I/O,函数的声明太复杂。下面通过编写一个程序来综合的演示多路I/O,非阻塞I/O,以及FIFO。 Lets go!,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报