嵌入式Linux进程控制开发——进程控制编程

1.fork()

(1)函数说明

        fork()函数用于在已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。子进程可以看做父进程的复制品,继承了父进程的整个地址空间,包括进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程独有的只有它的进程号、资源使用和计时器等。fork()函数在父进程中返回子进程的进程号,而在子进程中返回0,由此区分父子进程,使其二者做不同的操作。

(2)函数语法

fork()函数语法要点
所需头文件

#include <sys/types.h> //提供类型pid_t的定义

#include <unistd.h>

函数原型 pid_t fork(void)
函数返回值 0:子进程
子进程ID(大于0的整数):父进程
-1:出错

(3)使用实例

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

int main(void)
{
    pid_t result;

    result = fork();

    if(result == -1)
    {
        printf("Fork 错误\n");
    }
    else if(result == 0)
    {
        printf("返回值:%d,子进程号:%d\n",result,getpid());
    }
    else
    {
        printf("返回值:%d,父进程号:%d\n",result,getpid());
    }
    return 0;
}

2.exec函数族

(1)函数说明

        当fork()函数创建一个子进程之后,可以通过exec()函数族来启动另一个程序。这个程序可以是二进制文件,也可以是脚本文件。在Linux中使用exec函数族主要有以下两种情况:

        ① 当进程认为自己不能再为系统和用户做出任何贡献时,可以调用exec函数族中的任何一个函数让自己重生。

        ② 如果一个进程想执行另一个程序,那么它就可以调用fork()函数新建一个进程,然后通过exec函数族打开这个程序。

(2)函数语法

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 *path,const char *arg,...)
int execvp(const char *path,char *const argv[])
函数返回值 -1:出错
exec函数名对应含义
前4位 统一为:exec
第5位 l:列表传递参数 execl、execle、execlp
v:数组传递参数 execv、execve、execvp
第6位 e:传递环境变量 execle、execve
p:可执行文件查找方式为文件名 execlp、execvp

(3)使用实例

(1)使用execlp()                                           //l列表,p文件名查找
     execlp("ps","ps","-ef",NULL);                         //注意结尾必须是NULL
(2)使用execl()                                            //l列表,无p表示路径查找
     execl("/bin/ps","ps","-ef",NULL);
(3)execle()                                              //l列表,e环境变量
     char *envp[]={"PATH=/tmp","USER=JIWilliam",NULL};     //定义环境变量,结尾必须是NULL
     execle("/usr/bin/env","env","NULL",envp);
(4)execve()                                              //v数组,e环境变量
     char *arg[]={"env",NULL};                             //数组参数
     execve("/usr/bin/env",arg,envp);

3.exit()和_exit()

(1)函数说明

        相同点:当进程执行exit()或_exit()时,进程会无条件地停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。

        区别:_exit()直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构。exit()在退出之前要检测文件的打开情况,把文件缓冲区中的内容写回文件。而_exit()直接跳过这一步,因此容易使缓冲区中的数据丢失。

(2)函数语法

exit()和_exit()函数语法
所需头文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函数原型 exit:void exit(int status)
_exit:void _exit(int status)
函数传入值

status是一个整形的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束;其他数值表示出现了错误,进程非正常结束。

在实际编程中,可以用wait()系统调用接收子进程的返回值,从而针对不同的情况进行不同的处理

(3)使用实例

printf()函数使用的是缓冲IO方式,该函数在遇到“\n”换行符时自动从缓冲区中将记录读出。

/* exit() */
main()
{
    printf("Using exit...\n");
    printf("This is the content int buffer");
    exit(0);
}
输出结果:
Using exit...
This is the content int buffer
结果分析:
printf("Using exit...\n");               //语句结尾加了换行符,于是缓冲IO自动将其输出
printf("This is the content int buffer");//语句结尾未添加换行符,保存于缓冲IO中,当下次遇到/n时才输出
exit(0)结束进程时会将缓冲IO中的内容输出,于是两条语句都被打印。
/* _exit() */
main()
{
    printf("Using _exit...\n");
    printf("This is the content in buffer");
    _exit(0);
}
结果输出:
Using _exit...
结果分析:
printf("Using _exit...\n");              //结尾添加换行符,打印
printf("This is the content in buffer"); //结尾未添加换行符,不打印
_exit(0)结束进程时,直接结束,跳过了输出缓冲IO内容的步骤,所以第二条语句不打印。
如果在第二条语句后添加\n则结果和exit()一样,一般情况下最好使用exit()。

4.wait()和waitpid()

(1)函数说明

        wait()函数使父进程阻塞,直到一个子进程结束或者该进程接收到指定的信号为止。如果该父进程没有子进程或其子进程已经结束,则wait()立即返回。

        wait()函数可视为waitpid()函数的一个特例,waitpid()函数有诸多选项,功能更广泛。

(2)函数语法

wait()函数语法
所需头文件

#include <sys/types.h>

#include <sys/wait.h>

函数原型 pid_t wait(int *status)
函数传入值

这里的status是一个整形指针,是该子进程退出时的状态

status若不为空,则通过它可以获得子进程的结束状态

另外,子进程的结束状态可由Linux中一些特定的宏来测定

函数返回值

成功:已结束运行的子进程的进程号

失败:-1

waitpid()函数语法
所需头文件

#include <sys/types.h>

#include <sys/wait.h>

函数原型 pid_t waitpid(pid_t pid,int *status,int options)
函数传入值 pid pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没结束,waitpid()就会一直等下去
pid=-1:等待任何一个子进程退出,此时和wait()作用一样
pid=0:等待其组ID等于调用进程组ID的任一子进程
pid<-1:等待其组ID等于pid的绝对值的任一子进程
status 同wait()
options WHOHANG:若由pid指定的子进程不立即可用,则waitpid()不阻塞,此时返回值为0
WUNTRACED:若实现某支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态
0:同wait(),阻塞父进程,等待子进程退出
函数返回值 正常:已经结束运行的子进程的进程号
选用WHOHANG且没有子进程退出:0
调用出错:-1

(3)使用实例

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

int main()
{
    pid_t pc,pr;

    if((pc = fork()) < 0)
    {
        printf("fork error\n");
        exit(1);
    }
    else if(pc == 0)
    {
        sleep(5);
        exit(0);
    }
    else
    {
        do
        {
            pr = waitpid(pc,NULL,WNOHANG);
            if(pr == 0)
            {
                printf("The child process has not exited.\n");
                sleep(1);
            }
        }while(pr == 0);

        if(pr == pc)
        {
            printf("Get child process exit code:%d\n",pr);
        }
        else
        {
            printf("error.\n");
            exit(1);
        }
    }
    return 0;
}

输出结果:
The child process has not exited.
The child process has not exited.
The child process has not exited.
The child process has not exited.
The child process has not exited.
Get child process exit code:29477

PS:若将pr = waitpid(pc,NULL,WNOHANG); 改为 pr = waitpid(pc,NULL,0);
则父进程会阻塞,直到子进程退出。
输出结果:Get child process exit code:29477

猜你喜欢

转载自blog.csdn.net/q1449516487/article/details/81462294