linux C/C++:进程原语
1. 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 
2. 进程环境 
在libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。用以下代码可以查看当前进程的所有环境变量的信息。
#include <stdio.h> 
int main(void)
{
    extern char **environ;
    int i;
    for(i = 0; environ[i] != NULL;  i++)
    printf("%s\n", environ[i]);
    return 0;
}运行结果用键值对的形式展示环境变量的信息。几个常见的环境变量解释: 
PATH:可执行文件的搜索路径。 
SHELL:当前使用的shell。 
HOME:当前用户的主目录路径。 
3.  进程状态 
4种主要的进程状态:运行、就绪、挂起、终止。 
4.  进程原语 
在liunx中使用函数fork创建新的进程。
#include <unistd.h>
pid_t fork(void);函数特点:调用一次,返回两次。 
在父进程中,返回创建的子进程的pid;在子进程中返回0;出错,返回-1。 
一个创建子进程的实例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
void sys_err(char *s)
{
    perror(s);
    exit(1);
}
int main(void)
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
        sys_err("fork");
    else if (pid > 0)
    {
        /* parent process */
        printf("I am parent,my pid is %d, my parent pid is %d\n", getpid(), getppid());
        sleep(1);   //休眠1秒,防止父进程过早退出
    }
    else
    {
        /* child process */
        printf("I am child,my pid is %d, my parent pid is %d\n", getpid(), getppid());
    }
    return 0;
}
//I am child, my pid is 15057, my parent pid is 15056
//I am parent, my pid is 15056, my parent pid is 5292#include <unistd.h>
#include <sys/types.h>   //定义了pid_t、uid_t、gid_t
pid_t getpid(void);   //获取当前进程的pid
pid_t getppid(void);  //获取当前进程父进程的pid
uid_t getuid(void);   //返回实际用户id
uid_t geteuid(void);  //返回有效用户id
gid_t getgid(void);   //返回实际用户组id
gid_t getegid(void);  //返回有效用户组id所有id都是正数。 
父进程和子进程的关系: 
1.子进程复制了父进程的PCB(除了pid)和代码段以及数据区。 
2.用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。 
5.  exec族
#include <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[]);只需弄懂了execl的使用,其它的举一反三了:path指出了新可执行程序的路径,后面的arg,即是提供的参数。 
使用execl函数更改程序的执行:
//show.c
#include <stdio.h>
int main(int argc, char **argv)
{
    int i = 0;
    while(i < argc)
        printf("%s\n", argv[i++]);
    return 0;
}
//app.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    if(argc < 2)
    {
        fprintf(stderr, "usage:app newapp ...");
        exit(1);
    }
    printf("zhangxiang\n");
    //$ argv[1] zx zhangxiangDavid@126.com
    execl(argv[1], "zx", "zhangxiangDavid@126.com", NULL);  //NULL用于指明参数列表的结束
    printf("David\n");
    return 0;
}
$ gcc show.c -o show
$ gcc app.c -o app
$ app show
zhangxiang
zx
zhangxiangDavid@126.com执行printf(“zhangxiang\n”);了后,程序的代码段被替换,所以原程序的printf(“David\n”);不会被执行。
l 命令行参数列表 
p 搜素file时使用path变量 
v 使用命令行参数数组 
e 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量 
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。 
6.  wait()、waitpid() 
僵尸进程::子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程。 
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程领养孤儿进程。 
子进程结束后,PCB仍然滞留在内存。父进程可以通过子进程的PCB来获知子进程的退出状态:正常退出时的退出码、不正常退出时,是被哪个信号终止的。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);函数说明: 
参数status为传出参数,用于记录退出状态。 
当没有子进程退出时,wait调用会阻塞当前进程。 
成功,返回子进程的pid; 
失败,返回-1;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
    pid_t pid, wpid;
    pid = fork();
    if(0 == pid)
    {
        printf("in child\n");
        sleep(2);
        printf("child exit\n");
    }
    else if(pid > 0)
    {
        while(1)
        {
            wpid = wait(NULL);
            printf("in parent %d\n", wpid);
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        exit(1);
    }
    return 0;
}
//in child
//child exit
//in parent 27909
//in parent -1
//in parent -1
//^cwait()会使父进程阻塞,为了不阻塞,需使用waitpid()
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);函数说明: 
pid指明了需回收哪个子进程的PCB; 
通过指定options的值,更改函数运行状态。(特别地,指定WNOHANG,将不会阻塞)。 
指定WNOHANG,非阻塞后。若没有进程退出,返回0,其它同wait。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
    pid_t pid, wpid;
    pid = fork();
    if(0 == pid)
    {
        printf("in child\n");
        sleep(2);
        printf("child exit\n");
    }
    else if(pid > 0)
    {
        while(1)
        {
            wpid = waitpid(0, NULL, WNOHANG);
            printf("in parent %d\n", wpid);
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        exit(1);
    }
    return 0;
}
//in parent 0
//in child
//in parent 0
//child exit
//in parent 28700
//in parent -1
//in parent -1
//^c版权声明:本文为博主原创文章,转载,请注明出处。
原文:http://blog.csdn.net/zhangxiangdavaid/article/details/46875181