第一章 第五节

进程与控制

该小节比较粗略的阐述了unix操作系统中用于进程控制的三个函数,分别为 : fork , exec, waitpid, 其中 exec 有五种变体, 这些变体实现的功能全部相同,只是参数不相同而已,他们统称为__exec__函数。

API

#include<unistd.h>
#include<sys/types.h>
pid_t fork(void);

pid是一个宏定义,根据平台不同而不同,大多数情况都是一个int,该函数的难点在与对进程的理解,因为该函数会创建一个进程,创建进程以后,当前的调用进程会“分叉”, 所以该函数会在父进程与子进程中分别返回不同的值, fork 成功之后会获得父进程空间的数据,堆栈资源的副本,就是深拷贝的数据副本,2个进程同时独自享有这些资源,在fork成功之后,我们无法得知子进程与父进程的运行的先后顺序,这依赖于具体实现,虽然进程创建成功之后有了2个“同时”运行的进程, 但是我们的代码是只有一份(其实是2份,但是运行的效果是相同的,无法分别),所以就出现了这种情况:

if(pid<0)
{
fprintf(stderr,"错误!");
}
elseif(pid==0)
{
printf(" child running");
exit(0);
}
else
{
printf("father running and child is : %d\n",pid);
}

我们在程序中可以判断到底是哪个进程在运行,同时根据不同的进程采取不同的运行路径,为什么一段代码可以被2个进程执行呢,因为2个进程拥有相同的资源。即上面的代码其实是2个进程同时运行的(同时运行相同的代码,不是真的2个进程在运行同一段代码),只是看起来像是只有一个进程而已。

exec 系列函数

<unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]);

其中只有execve是真正的api,其他的函数都是对此函数的封装,为了实现方便快捷的调用而已。该函数首先查找要执行的文件,第一个参数可以是文件路径和文件名,也可以只是文件名。函数不同,参数不同,不过大致都是可执行文件的位置,其中第二个参数必须是可执行文件的 文件名, 可以存在于arg[0], 或者是arg0 , 总之都要是文件名, 往后的参数都是该命令的参数,该函数参数列表的结尾部分 必须是NULL, 不管是字符指针数组还是单独的若干个字符数组,其最后的一项必须为NULL。

该函数会替换当前正在执行进程本身,意思就是说当该函数执行成功,当前进程就会变成该函数启动的进程,并且调用进程会停止运行,当exec的进程执行完毕之后,调用进程也不会继续执行,因为它不是被挂起了,而是被替换掉了。

#include<sys/types.h>

#include<sys/wait.h>
pid_t waitpid(pid_t pid,int * status,int options);

该函数用来监控进程状态,第一个参数是目标进程pid,第二个参数是进程状态返回地址,可选参数提供了多种可选方案。

参数pid也可以有别的可选值:

pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。
pid=-1 等待任何子进程,相当于 wait()。
pid=0 等待进程组识别码与目前进程相同的任何子进程。
pid>0 等待任何子进程识别码为 pid 的子进程。

可选参数含义如下,摘选自百度百科

WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。

WUNTRACED 若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会。

WIFSTOPPED(status)宏确定返回值是否对应与一个暂停子进程。

子进程的结束状态返回后存于 status,下面有几个宏可判别结束情况:

WIFEXITED(status)如果若为正常结束子进程返回的状态,则为真;对于这种情况可执行WEXITSTATUS(status),取子进程传给exit或_eixt的低8位。

WEXITSTATUS(status)取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。

WIFSIGNALED(status)若为异常结束子进程返回的状态,则为真;对于这种情况可执行WTERMSIG(status),取使子进程结束的信号编号。

WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。

WIFSTOPPED(status) 若为当前暂停子进程返回的状态,则为真;对于这种情况可执行WSTOPSIG(status),取使子进程暂停的信号编号。

WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先用 WIFSTOPPED 来判断后才使用此宏。

如果执行成功返回子进程pid, 失败则返回-1, 错误识别码在 errno 中。

该节的例子程序

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> #define MAXLINE 255 char ** string_split(char*, char*);
int parse_cmd(char*); char **
string_split(char * str, char * split)
{
char ** ret_split = (char **)malloc(sizeof(char * ) * MAXLINE);
char * temp;
temp = strtok(str, split);
int i = 0;
while(temp)
{
*(ret_split + i) = temp;
i++;
temp = strtok(NULL, split);
}
*(ret_split +i) = NULL; return ret_split;
} int
parse_cmd(char * cmd)
{
char ** cmds = string_split(cmd, " ");
int signal = execvp(*(cmds + 0), cmds);
return signal;
} int
main(void)
{
char buf[MAXLINE];
pid_t pid;
int status; printf("%%");
while(fgets(buf, MAXLINE, stdin) != NULL)
{
buf[strlen(buf) - 1] = 0;
if((pid = fork()) < 0)
{
printf("fork error");
}
else if(pid == 0)
{
parse_cmd(buf);
printf("could not execute : %s\n", buf);
exit(127);
}
if((pid = waitpid(pid, &status, 0)) < 0)
{
printf("waitpid error");
}
printf("%d\n", status);
printf("%%"); } exit(0);

}

该程序是书中程序的变种,书中的程序是不能带参数执行命令的,我这里简单的处理了一下参数,这是可独立变异运行的版本,不需要ourhdr.h 头文件的支持。

unix-环境高级编程-读书笔记与习题解答-第三篇的更多相关文章

  1. unix 环境高级编程 读书笔记与习题解答第四篇

    第一章 第六节 第一小节 这一章没有程序设计和API方面的深入学习,而是注重介绍了unix操作系统中的原始数据类型和系统原型函数,错误处理方面的知识. ____unistd.h____ 该文件包含了u ...

  2. unix环境高级编程-读书笔记与习题解答-第一篇

    从这周开始逐渐的进入学习状态,每天晚上都会坚持写c程序,并且伴随对这本书的深入,希望能写出更高质量的读书笔记和程序. 本书的第一章,介绍了一些关于unix的基础知识,在这里我不想去讨论linux到底是 ...

  3. unix 环境高级编程-读书笔记与习题解答-第二篇

    第四节 输入与输出 上次的笔记中写到的 open, read, write, lseek 以及close ,都是不带缓存的IO函数,这些函数都使用文件描述符进行工作. 上一篇笔记用到的 read(ST ...

  4. [置顶] 文件和目录(二)--unix环境高级编程读书笔记

    在linux中,文件的相关信息都记录在stat这个结构体中,文件长度是记录在stat的st_size成员中.对于普通文件,其长度可以为0,目录的长度一般为1024的倍数,这与linux文件系统中blo ...

  5. [置顶] 文件io(一)--unix环境高级编程读书笔记

    unix-like(后面以linux为例)系统中的文件操作只需要五个函数就足够了,open.close.read.write以及lseek.这些操作被称为不带缓存的io,这里有必要说一下带缓存和不带缓 ...

  6. unix进程的环境--unix环境高级编程读书笔记

    http://blog.csdn.net/xiaocainiaoshangxiao/article/category/1800937

  7. unix环境高级编程 读书笔记

    1.上班业余时间把书下载下来,第一章读完了,但是程序只能回家运行啦!Fighting!

  8. Unix环境高级编程学习笔记——fcntl

    写这篇文正主要是为了介绍下fcntl,并将我自己在学习过程中的一些理解写下来,不一定那么官方,也有错误,希望指正,共同进步- fcntl: 一个修改一打开文件的性质的函数.基本的格式是 int fcn ...

  9. 《UNIX环境高级编程》笔记--UNIX标准化及实现

    1.UNIX标准化 1.1.ISO C 1989 年后期,C程序设计语言的ANSI(American National Standards Institute) 标准X3. 15 9-1989得到批准 ...

随机推荐

  1. Linux查看系统资源占用

    Linux查看系统资源占用 在系统维护的过程中,随时可能有需要查看 CPU和内存的使用率,并根据相应信息分析系统状况的需求.本文介绍一下几种常见的Linux系统资源查看命令. 1.总体内存占用的查看 ...

  2. StopWatch

    附件 http://download.csdn.net/detail/teststudio/6575241 主窗体UNIT unit MainForm; interface uses Windows, ...

  3. android中listview的一些样式设置

    在Android中,ListView是最常用的一个控件,在做UI设计的时候,很多人希望能够改变一下它的背景,使他能够符合整体的UI设计,改变背景背很简单只需要准备一张图片然后指定属性 android: ...

  4. Androidannotation使用之@Rest与server交互的JSON数据转换(二)

    开篇 之前的一篇博客:Androidannotation使用之@Rest获取资源及用户登录验证(一):http://blog.csdn.net/nupt123456789/article/detail ...

  5. 开启MYSQL远程连接权限

      开启MYSQL远程连接权限   1 2 3 4 5 //建议设置固定IP mysql> GRANT ALL PRIVILEGES ON *.* TO root@"8.8.8.8&q ...

  6. Qt 学习之路:线程总结

    前面我们已经详细介绍过有关线程的一些值得注意的事项.现在我们开始对线程做一些总结. 有关线程,你可以做的是: 在QThread子类添加信号.这是绝对安全的,并且也是正确的(前面我们已经详细介绍过,发送 ...

  7. iOS-UIResponse之事件响应链及其事件传递

    UIResponse之事件响应链及其事件传递 我们的App与用户进行交互,基本上是依赖于各种各样的事件.一个视图是一个事件响应者,可以处理点击等事件,而这些事件就是在UIResponder类中定义的. ...

  8. xp系统

    产品密钥 MRX3F-47B9T-2487J-KWKMF-RPWBY(亲测可用)

  9. 4 - SQL Server 2008 之 使用SQL语句删除表格

    使用删除表格的SQL命令与删除数据的命令一样,只是删除的是表格这个对象, 语法如下:DROP TABLE 表名 一般在删除表格之前,需判断这个表格存不存在,存在则删除,不存在则不进行执行任何代码. 代 ...

  10. 委托、 Lambda表达式和事件——委托

    简单示例 /* * 由SharpDevelop创建. * 用户: David Huang * 日期: 2015/7/27 * 时间: 10:22 */ using System; namespace ...