zoukankan      html  css  js  c++  java
  • unix-环境高级编程-读书笔记与习题解答-第三篇

    第一章 第五节

    进程与控制

    该小节比较粗略的阐述了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
    ",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
    ", buf);
            		exit(127);
        	}
        	if((pid = waitpid(pid, &status, 0)) < 0)
        	{
            		printf("waitpid error");
        	}
        	printf("%d
    ", status);
        	printf("%%");
    
    	}
    
     exit(0);
    

    }

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

  • 相关阅读:
    linux 配置nginx+php-cgi
    有个故事
    2014短学期实习报告
    快速排序
    C++之共用体
    不能言传,等于不会
    java 动态绑定
    编程的理论深度
    Java 多客户端版 2048 源码
    热河看待苦难
  • 原文地址:https://www.cnblogs.com/youngershen/p/4004652.html
Copyright © 2011-2022 走看看