当前位置:首页 > 资讯 > info6 > 正文

linux_c:进程(三)

发表于: 2016-07-30   作者:championhengyi   来源:转载   浏览:
摘要: 进程退出在Linux下系统进程退出的方法分为正常退出和异常退出两种正常退出:在main函数中执行return调用exit函数调用_exit函数异常退出:调用abort函数进程收到某个信号,而该信号使程序终止补充:exit和return的区别:exit是将控制权交给系统,return将控制权交给函数exit和abort的区别:exit是正常终止,abort是异常终止exit(intexit_code

进程退出

在Linux下系统进程退出的方法分为正常退出和异常退出两种
正常退出:

  • 在main函数中执行return
  • 调用exit函数
  • 调用_exit函数

异常退出:

  • 调用abort函数
  • 进程收到某个信号,而该信号使程序终止

补充:

  • exit和return的区别:exit是将控制权交给系统,return将控制权交给函数
  • exit和abort的区别:exit是正常终止,abort是异常终止
  • exit(int exit_code):exit中的参数为0代表正常终止,若为其他值表示异常终止
  • exit和_exit的区别:exit在stdlib.h中声明,而_exit在unistd.h中声明,exit要先执行一些清除操作,然后将控制权交给内核,而_exit会执行后立即返回给内核

僵尸进程:

  • 当父进程先于子进程退出,子进程会变成孤儿进程而被init收养,当子进程先于父进程退出,父进程还没有调用wait函数等待的话,子进程就会变成僵尸进程
  • 有人会说,子进程不是已经结束了吗,为什么会变成僵尸进程?其实,子进程结束之后(父进程没有结束),系统只是释放了大部分资源,还有一部分资源,如子进程的进程id号,以及一些退出时的状态,运行的时间等等都是没有被释放的,因为它不知道父进程什么时候会再此调用它,所以如果父进程没有等待的过程,那么子进程的这些资源就没有办法被回收,也就变成了僵尸进程
  • 僵尸进程的危害:系统之中的进程id号是有限的,如果系统的僵尸进程把进程id号占用完,那就无法在创建新的进程,占用系统资源

执行新程序

当创建了新的子进程之后,我们一般是不会让它做和父进程一样的事情的,这样创建出来的新进程也就没啥了意义,所以,我们可以使用exec函数族,来使新的进程去执行其他的任务
注意: exec调用并没有生成新进程,一个进程一旦调用了exec函数,那么它的原有的代码段会被替换为新的代码段,并废弃原有的数据段和堆栈段,并为新的程序分配新的数据段和堆栈段,唯一保留的就是进程id。

#include<unistd.h>
int execve(const char *path, char *const argv[], char * const envp[])
int execv(const char *path, char *const argv[])
int execle(const char *path, const char *arg, ...)
int execl(const char *path, const char *arg, ...)
int execvp(const char *file, char *const argv[])
int execlp(const char *file, const char *arg, ...)
//关于envp这个东西,实际上它是当前系统的环境变量,它是main函数里面的,main函数的完整形式:
//int main(int argc, char *argv[], char *envp[])
//通过打印envp,就可以得到环境变量的值

对于exec函数族各个函数的解释

无论是哪个exec函数,都是将可执行程序的路径,命令行参数和环境变量传递给可执行程序的main函数的

  • execv函数:execv函数是通过路径名方式调用可执行文件作为新的进程映像,它的argv参数用来提供给main函数的argv参数。argv参数是一个以NULL结尾的字符串数组
  • execve函数:参数path是将要执行的程序的路径名,参数argv,envp与main函数的argv,envp对应
  • execl函数:该命令和execv命令相似,只是再传递argv参数的时候,每个命令行参数都要声明为一个单数的参数,最后以NULL结束
  • execle函数:该函数和execl用法相似,只是要显式的指定环境变量,环境变量位于NULL之后
  • execvp函数:该函数和execv用法类似,只是如果该参数包含/,就相当于路径名,而如果没有/,函数就到PATH环境变量定义的目录下寻找可执行文件
    execlp函数:该函数类似execl函数,它们的区别和execvp与execv的区别一样
    exec函数族中只有execve是系统调用,其他都是库函数,他们运行时都调用execve
    注:我习惯使用execvp函数,但要记住execve函数
    这些函数一般情况下是不会返回的,因为进程的执行映像已经被替换,没有接受返回值的地方,如果有一个错误事件,返回-1,这些错误通常是由文件名或参数错误引起的,有兴趣的请自行百度
    linux下exec函数族是可以执行二进制的可执行文件的,也可以执行shell脚本程序,但shell脚本必须以下面的格式开头,第一行为:#interpretername[arg]。其中interpretername可以是shell或其他解释器,arg是传递给解释器的参数

附exec函数实用源码:

//用来替换进程映像的程序
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>

int main(int argc, char * argv[], char ** environ)
{
    int i;

    printf("I am process image!\n");
    printf("my gid: %d, my parent gid: %d\n", getpid(), getppid());
    printf("my uid: %d, my gid: %d\n", getuid(), getgid());

    for(i=0; i<argc; i++)
    {
        printf("argv[%d]: %s\n", i, argv[i]);
    }

    return 0;
}
//exec函数,这里使用execve函数
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<wait.h>

int main(int argc, char *argv[],char ** environ)
{
    int pid;
    int stat_val; // 存储子进程退出时的状态

    printf("execve example!\n");

    pid = fork();

    switch(pid)
    {
        case -1:
            perror("process creation failed!\n");
            exit(1);
        break;

        case 0:
            printf("I am child process!\n");
            printf("my pid: %d, my parent: %d\n", getpid(), getppid());
            printf("my uid: %d, my gid: %d\n", getuid(), getgid());

            execve("processimage", argv, environ);

            printf("parent never go to here!\n");
            exit(0);
        break;

        default:
            printf("I am parent process!\n");
        break;
    }

    wait(&stat_val);

    return 0;
}
//子进程是永远不会执行到printf("parent never go to here!\n")的,因为调用execve函数之后,子进程已经被新的执行映像所代替

注意:

执行新程序后除了保持原来的进程id,父进程id,实际用户id和实际组id外,还保持了许多原有的特性:

  • 当前工作目录
  • 根目录
  • 创建文件时所用的屏蔽字
  • 进程信号屏蔽字
  • 未决警告
  • 和进程相关的使用处理器的时间
  • 控制终端
  • 文件锁

linux_c:进程(三)

编辑推荐
1. 引言 先来个比喻手法: 如果把上课的过程比作进程,那么每个学生就是一个线程,他们共享教室,即
task_struct 中有这么几个和进程ID有关的字段 pid_t pid; pid_t tgid; .... struct pid_link pids[P
实验三 进程调度 一、实验目的 1、 理解有关进程控制块、进程队列的概念。 2、 掌握进程优先权调度
i=0时,主进程和其创建的子进程分别打印’-‘, 打印2个 i=1时,之前两个进程打印’-‘, 每个进程又
在计算机一开始工作的时候,其实就是多个进程并行的开始!! 在操作系统的源代码中main函数创建了第
程序(港台称程式)和线程 程序不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行。
1. contiki中进程的类型 由图示我们可以看到,contiki中包含两种类型的进程,preemptive(可抢占的)和c
(转自)作者:mickole 出处:http://www.cnblogs.com/mickole/ 本节目标: 复制进程映像 fork系统调
本节目标: 复制进程映像 fork系统调用 孤儿进程、僵尸进程 写时复制 一,进程复制(或产生) 使用f
文章目录: 1. 引子: 2. 获取当前系统下所有进程: 3. 服务管理(安装,启动,停止,卸载): 4.
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号