Linux C 编程学习-----Linux 进程

/********************************************************************/
fork 函数
/********************************************************************/

    #include<sys/types.h>  //提供类型 pid_t 的定义
    #include<unistd.h>
    
    pid_t fork(void);
    
    /* 调用 fork 函数,其返回值赋给 result */
    int result = fork();
    if (result == -1)
    {
        perror("fork");
        exit(-1);
    }    
    else if (fork == 0)
    {
        //子进程相关语句
    }
    else
    {
        //父进程相关语句
    }

    
/********************************************************************/
exec 函数
/********************************************************************/

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

    
    例子:
    1.  int execlp(const char *file, const char *arg,....)

            /* 在当前系统默认的环境变量 PATH 中查找可执行文件 */
            if (fork() == 0)
            {
                //调用 execlp 函数,这里相当于调用了 “ls -l” 命令
                if (execlp ("ls", "ls", "-l", NULL)<0)
                {
                    perror("execlp error!");
                }
            }

            
    
                    
    2. int execl(const char *path, const char *agr,...)

            /* 使用 execl 函数时,需要给出完整的文件路径来查找对应的可执行文件 */
            if (fork() == 0)
            {
                if (execl ("/bin/ls", "ls", "-l", NULL)<0)
                {
                    perror("execl error!");
                }
            }

            
    3. int execle(const char *path, const char *arg,....,char *const envp[])

            /* 使用 execle 时可以将环境变量添加到新建的子进程中去,这里先把环境变量构造成指针数组的方式来传递 */
            // 命令参数列表必须以 NULL 结尾
            char *envp[]={"PATH=/tmp","USER=sunq", NULL};
            if (fork() == 0)
            {
                //调用 execle 函数,注意这里也要指出 env 的完整路径
                if (execle("/bin/env", "env", NULL, envp)<0)
                {
                    perror("execle error!");
                }
                
            }

    
    4. int execve(const char *path, char *const argv[], char *const envp[])

            /* 使用 execve 函数时,通过构造指针数组的方式来传递参数,注意参数列表一定要以 NULL 作为结尾标识符 */
            char *arg[]={"env", NULL};
            char *envp[]={"PATH=/tmp","USER=sunq",NULL};
            if (fork() == 0)
            {
                if (execve("/bin/env", arg, envp)<0)
                {
                    perror("execve error!");
                }
                
            }

            
/********************************************************************/
exit 和 _exit
/********************************************************************/

    exit :#include<stdlib.h>
    _exit: #include<unistd.h>
    
    void exit(int status);
    void _exit(int status);
    /* 利用该参数 status 传递进程结束时的状态。一般来说,0表示正常结束;其他的数值表示出现错误,进程非正常结束 */

    
    这两个函数调用很简单,输入状态参数即可,如下:

        exit(0);
        _exit(-1);


/********************************************************************/
wait 和 waitpid
/********************************************************************/

wait 函数可以使父进程(也就是调用 wait 的进程)阻塞,直到任意一个子进程结束或者父进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则 wait 函数会立即返回。

waitpid 的作用和 wait 一样,但它并不一定要等待第一个终止的子进程。它还有若干选项,如可提供一个非阻塞版本的 wait 功能,也能支持作业控制。实际上 wait 函数只是 waitpid 函数的一个特例,在 Linux 内部实现 wait 函数时直接调用的就是 waitpid 函数。

#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int *status) //等待子进程结束,同时接受子进程退出时的状态。
pid_t waitpid(pid_t pid,//等待结束的进程类型
              int *status//同 wait
              int options)//选项

    若是 status 位空,则不保存子进程的退出状态。
    
    成功时返回子进程的子进程号或0(调用成功但子进程还未退出);
    失败时返回-1;
    
    调用 waitpid ,且父进程不阻塞:

  pr=waitpid(pid,NULL,WNOHANG);

        
        
        
/********************************************************************/
避免僵尸进程实例
/********************************************************************/
方法1:父进程调用 wait/waitpid 等待子进程结束,但这样做有一个弊端就是在子进程结束前父进程会一直阻塞,不能做任何事情。
方法2:调用两次 fork 函数(这个方法好!);

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

int main()
{
    pid_t pid;
    if((pid = fork()) < 0)
    {
        perror("fork");
    }
    else if(pid == 0)
    {
        if((pid = fork()) < 0)
        {
            perror("fork");
        }
        else if(pid > 0)
        {
            exit(0);
        }
        else
        {
            sleep(2);
            printf("second child, parient pid = %d\n", getpid());
            exit(0);
        }
    }
    else
    {
        //其他进程
    }
}


    因为子进程 1 创建完子进程 2 后退出,所以子进程 2 变成了孤儿进程,自动被 init 进程收养。当子进程 2 结束时,init 进程对子进程 2 进程回收,避免了僵尸进程的出现。

你可能感兴趣的:(linux,进程)