array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 第6章 进程控制(3)_wait、exec和system函数 - 爱码网

5. 等待函数

(1)wait和waitpid

头文件

#include <sys/types.h>

#include <sys/wait.h>

函数

pid_t wait(int* status);

pid_t waitpid(pid_t pid, int* status, int options);

返回值

成功返回子进程ID,出错返回-1

功能

等待子进程退出并回收,防止僵尸进程的产生

参数

(1)status参数:

  ①为空时,代表任意状态结束的子进程;

  ②不为空时,则等待指定状态结束的子进程

(2)waitpid的pid参数

  ①pid == -1 :等待任一子进程,功能与wait等效。

  ②pid > 0 :等待其进程ID与pid相等的子进程

  ③pid == 0:等待其组ID等于调用进程的组ID的任一子进程

  ④pid < -1:等待其组ID等于pid的绝对值的任一子进程。

(3)options参数

  ①WNOHANG:如果pid子进程未结束则立即返回,不会阻塞,此时返回值为0。如果pid进程己退出,则返回这个进程的pid。

  ②WUNTRACED:使waitpid报告那些己经被停止的未报告子进程的状态。

备注

wait的waitpid的区别:

  ①在一个子进程终止前,wait使用调用者阻塞

  ②waitpid的options可使调用者不阻塞

  ③waitpid等待一个指定的子进程,而wait等待所有的子进程,返回任一终止子进程的状态。

(2)检查wait和waitpid函数返回的终止状态的宏

判断终止状态

获取终止状态值

说明

WIFEXITED(status)

WEXITSTATUS(status)

判断子进程是否正常终止及获取退出码

WIFSIGNAL(status)

WTERMSIG(status)

判断子进程是否异常终止及获取异常终止的信号编码

WIFSTOPED(status)

WSTOPSIG(status)

判断子进程是否被暂停及获取暂停的信号编码

【编程实验】判断进程的终止状态

//process_wait.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

void out_status(int status)
{
    if(WIFEXITED(status)){
        printf("normal exit: %d\n", WEXITSTATUS(status));
    }else if(WIFSIGNALED(status)){
        printf("abnormal terminate: %d\n", WTERMSIG(status));
    }else if(WIFSTOPPED(status)){
        printf("Stopped signal: %d\n", WSTOPSIG(status));
    }else{
        printf("unknow signal\n");
    }
}

int main(void)
{
    int status;
    pid_t pid;
   
   //第1个子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){ //child process
        printf("pid: %d, ppid: %d\n", getpid(), getppid());
        exit(0);  //正常终止
    }

    //等待子进程结束(也可防止僵尸进程)
    if(wait(&status) != pid)
          perror("wait error");
    out_status(status);
    printf("----------------------------------------\n");
    
    //第2个子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){ //child process
        printf("pid: %d, ppid: %d\n", getpid(), getppid());
        abort();  //异常终止
    }

    //等待子进程结束(也可防止僵尸进程)
    if(wait(&status) != pid)
          perror("wait error");
    out_status(status);
    printf("----------------------------------------\n");

    //第3个子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){ //child process
        printf("pid: %d, ppid: %d\n", getpid(), getppid());
        int i = 3, j = 0;
        int k =  i /j;  //除0
        printf("k: %d\n", k);
    }

    if(wait(&status) != pid)
          perror("wait error");
    out_status(status);
    printf("----------------------------------------\n");
 
    //第4个子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){ //child process
        printf("pid: %d, ppid: %d\n", getpid(), getppid());
        pause();  //暂停,需要用带WUNTRACED的waipid来等待。
                  //同时,该子进程需发kill -SIGSTOP 来结束
    }
    //阻塞方式
    waitpid(pid, &status, WUNTRACED);

//    //非阻塞方式
//   do
//    {
//        //当waitpid返回0,表示子进程未结束
//        pid = waitpid(pid, &status, WNOHANG |  WUNTRACED);
//        
//        if (pid == 0) sleep(1);
//    }while(pid == 0);

    out_status(status);

    return 0;
}
/*输出结果:
pid: 1686, ppid: 1685
normal exit: 0
----------------------------------------
pid: 1687, ppid: 1685
abnormal terminate: 6
----------------------------------------
pid: 1688, ppid: 1685
abnormal terminate: 8
----------------------------------------
pid: 1689, ppid: 1685
Stopped signal: 19
*/

6. exec函数

(1)exec函数的主要作用

  ①在fork函数创建子进程后,子进程往往要调exec函数来执行另一个程序。

  ②当进程调用exec函数时,该进程完全由新程序代换,替换原有进程的正文,而新程序则从其main函数开始执行。因为exec并不创建新进程,所以前后的进程ID并不改变。

  ③exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段

(2)函数原型

头文件

#include <unistd.h>

函数

int execl(const char* pathname, const char* arg0,…/*(char*)0*/);

int execv(const char* pathname, char* const argv[]);

int execle(const char* pathname, const char* arg0,…/*(char*)0,char* const envp[]*/);

int execve(const char* pathname, char* const argv[],char* const envp[]);

int execlp(const char* pathname, const char* arg0,…/*(char*)0*/);

int execvp(const char* pathname ,char* const argv[]);

返回值

出错返回-1,成功则不返回

功能

执行程序

参数

(1)argv参数为新程序执行main函数中传递的argv参数,最后一个元素为NULL。

(2)envp为进程环境表。

(3)execlp和execvp函数中的pathname,相对和绝对路径均可使用其它四个函数中的pathname只能使用绝对路径。相对路径一定要在进程环境表对应的PATHT中。

备注

(1execve函数为系统调用,其余为库函数。当成功执行execve后就不返回 execve后面的代码去执行,进程进入新的程序执行,最后从新程序中退出。但执行execve出错时,仍会返回原程序。

(2)函数名后带字母“l”,表示第2个参数为列表(List),列表中的第1个元素为要执行的程序名,最后一个参数必须为NULL。

(3)带“p”的函数,表示第1个参数可以是相对或绝对路径。如果是相对路径,则会在环境变量PATH指定的路径中搜索。p表示PATH

(4)带字母“v”表示参数列为通过一个字符串数组来传递,相当于main函数的argv参数,数组中的第1个元素必须是程序名,最后一个参数也必须为NULL。

(5)带“e”的函数,用户可以自己设置程序接收一个设置环境变量的数组。

(3)6个函数的关系

第6章 进程控制(3)_wait、exec和system函数 

(4)exec执行后新进程保留原进程的一些特性

  ①进程ID、父进程ID、实际用户和组ID、进程组ID

  ②会话ID、控制终端;

  ③当前工作目录、根目录

  ④文件锁,进程信号屏蔽、未处理信号、资源限制

  ⑤闹钟尚余留的时间、tms_utime、tms_stime、tms_cutime以及tms_cstime的值。

  ⑥对打开文件的处理与每个描述符的(close-on-exec)标志有关。如果此标志设置,则在执行exec时关闭该描述符,否则该描述符仍打开。(一般系统默认这个标志位是关闭,也可以用fcntl来设置该标志位)。

  ⑦在执行exec时会自动关闭打开的目录流(调用opendir函数打开的目录),也可以用fcntl函数为打开的目录流的描述符设置close-on-exec标志。

【编程实验】打开新程序

//process_exec.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

char* cmd1 = "cat";      //相对路径
char* cmd2 = "/bin/cat"; //绝对路径
char* argv1 ="/etc/passwd";
char* argv2 = "/etc/group";

int main(void)
{
    pid_t pid;
    
    //第1个子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){  //child process
        //调用exec函数执行新的程序
        //if(execl(cmd1, cmd1, argv1, argv2, NULL) < 0){ //错误,execl只能用绝对路径
        if(execl(cmd2, cmd1, argv1, argv2, NULL) < 0){
            perror("execl error");
            exit(1);
        }else{
            printf("execl %s success\n", cmd1); //不返回这里
        }

        //当exec成功调用后,执行流进入新的程序,不返回到这里。
        printf("after exec...\n");
    }
    //只有父进程会执行到这里,子进程因exec进入了新的程序
    wait(NULL); 
    printf("--------------------------------\n");

    //第2个子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){  //child process
        char* argv[4]={cmd1, argv1, argv2, NULL};
        if(execvp(cmd1, argv) < 0){
            perror("execvp error");
            exit(1);
        }else{
            printf("execvp %s success\n", cmd1); //不返回这里
        }
    }

    wait(NULL);

    return 0;
}

7. system函数

头文件

#include <stdlib.h>

函数

int system(const char* command);

返回值

成功返回执行命令的状态,出错返回-1

功能

简化exec函数的使用

备注

①system函数内部构建一个子进程由子进程调用exec函数

②/bin/bash -c "cmd"或者exec("bash","-c","cmd");

【编程实验】自定义system函数

//process_system.c

#include <unistd.h>
#include <stdlib.h>

const char* cmd1 = "date > s1.txt";
const char* cmd2 = "date > s2.txt";
//模仿system函数
void mysystem(const char* cmd)
{
    pid_t pid;

    //1.创建子进程
    if((pid = fork()) < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){//子进程
        //2. 通过exec函数创/bin/bash进程来执行命令
        if(execlp("/bin/bash", "bin/bash","-c", cmd, NULL) < 0){
            perror("execlp error");
            exit(1);
        }
    }else{  //父进程
        wait(0);
    }
}

int main(void)
{  
    system("clear"); //清屏
    system(cmd1);
    mysystem(cmd2); //自定义的mysystem

    return 0;
}

/*输出结果
root@bogon 6.process]# cat s1.txt              
2017年 01月 26日 星期四 19:26:23 CST
[root@bogon 6.process]# cat s2.txt              
2017年 01月 26日 星期四 19:26:23 CST
[root@bogon 6.process]# 
*/

相关文章: