• 进程终止,环境表以及在内存中布局和非局部跳转


    进程ID:
    每个linux进程都一定有一个唯一的数字标识符,称为进程ID(总是一个非负整数)

    进程终止:
    正常终止:
    1.从Main返回(return)
    2.调用exit (标准库)
    3.调用_exit或_Exit (内核提供)
    4.最后一个线程从启动例程返回
    5.最后一个线程调用pthread_exit
    异常终止:
    调用abort(信号相关)
    接收到一个信号并终止(信号相关)
    最后一个线程对取消请求做相应
    exit与_exit() 区别 是否刷新缓存区
    flush I/O
    atexit 函数

    exit:先刷新缓存区,然后结束进程 ,在结束之前调用信号注册函数atexit
    _exit:不刷新缓存区 直接从进程退出,由内核直接结束进程 没经过atexit

    exit.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
    
    int main(int argc,char *argv[]){
        if(argc<3){
            fprintf(stderr, "usage:%s file return|exit|_exit
    ", argv[0]);
            exit(1);
        }
    
        FILE *fp=fopen(argv[1],"w"); //双 引号
        char *str = "hellophp";
    
        fprintf(fp, "%s",str );
        if(!strcmp(argv[2],"return")){
            return 0;
        }else if(!strcmp(argv[2],"exit")){
            exit(0);
        }else if(!strcmp(argv[2],"_exit")){
            _exit(0);
        }else{
            printf("process error
    ");
        }
        return 0;
    }

    运行结果

    [root@centos1 exit]# ./a.out exit.txt exit
    [root@centos1 exit]# ./a.out _exit.txt _exit
    [root@centos1 exit]# ./a.out return.txt return
    [root@centos1 exit]# more *.txt
    ::::::::::::::
    _exit.txt
    ::::::::::::::
    ::::::::::::::
    exit.txt
    ::::::::::::::
    hellophp
    ::::::::::::::
    return.txt
    ::::::::::::::
    hellophp

    进程的环境表

    获取当前进程的环境表
    1.通过别的地方定义的 引入过来
    extern char **environ
    2.通过main的第三个参数

    进程中环境表操作
    #include <stdio.h>
    char *getenv(const char *name)
    返回:指向与name关联的value指针,若未找到则返回NULL

    #include <std;ib.h>
    int putenv(char *str);
    int setenv(const char *name,const char *value,int rewrite); //1非0表示覆盖
    int unsetenv(const char *name);
    返回:成功返回0,出错返回非0

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    
    extern char **environ;
    
    void showenv(char **env){
        int i=0;
        char *str;
        while ((str =env[i]) != NULL){
            printf("%s
    ",str );
            i++;
    
        }
    }
    int main(int argc,char *argv[],char *envp[]){
        printf("envrison=%p,envp=%p
    ",environ,envp );//2个变量地址值一样的
        //showenv(environ);
        //printf("-------
    ");
        //showenv(envp);
        printf("----------------------------
    ");
        char *oldpath=getenv("PATH");
        char *addpath=":/tmp/hkui";
        int newlen=strlen(oldpath)+1+strlen(addpath)+1;
        printf("newlen=%d
    ",newlen );
        char newpath[newlen];
        strcpy(newpath,oldpath);
        strcat(newpath,addpath);
    
    
        printf("oldpath:%s
    ",oldpath);
        setenv("PATH",newpath,1);
        printf("newpath:%s
    ",getenv("PATH"));
        putenv("NAME=HKUI2018");
        printf("NAME:%s
    ",getenv("NAME"));
    
    
        return 0;
    }

     进程在内存中布局

    正文段(代码段)
    初始化数据段(全局数据,静态变量)
    非初始化数据(全局数据,静态变量)
    堆(手动分配的内存空间 malloc)
    栈(一端封闭,一端开口)
    main参数

    进程在栈区实现非局部跳转
    头文件<setjmp.h>中的说明提供了一种避免通常的函数调用和返回顺序的途径,特别的,它允许立即从一个多层嵌套的函数调用中返回

    setjump,longjump
    #include <setjmp.h>
    int setjmp(jmp_buf env)
    返回:直接调用返回0,若从longjmp调用返回,则返回非0值(longjmp第二个参数 val)

    void longjmp(jmp_buf env,int val)

    setjmp()宏把当前状态信息保存到env中,供以后longjmp()恢复状态信息时使用。
    如果是直接调用setjmp(),那么返回值为0;如果是由于调用longjmp()而调用setjmp(),那么返回值非0
    setjmp()只能在某些特定情况下调用,如在if语句、 switch语句及循环语句的条件测试部分以及一些简单的关系表达式中
    longjmp()用于恢复由最近一次调用setjmp()时保存到env的状态信息。
    当它执行完时,程序就象setjmp()刚刚执行完并返回非0值val那样继续执行
    包含setjmp()宏调用的函数一定不能已经终止。
    所有可访问的对象的值都与调用longjmp()时相同,唯一的例外是,那些调用setjmp()宏的函数中的非volatile自动变量如果在调用setjmp()后有了改变,那么就变成未定义的

    非局部跳转应注意的问题
    自动,寄存器和易失变量
    寄存器中的变量再非局部跳转时可恢复原始值
    自动变量的潜在问题

    #include <stdio.h>
    #include <stdlib.h>
    #include <setjmp.h>
    
    jmp_buf jmp;
    int g_v=1;
    
    void fun(){
        printf("jmp=%d
    ",jmp );
        longjmp(jmp,1);
        printf("jmp=%d
    ",jmp );
    }
    
    int main(void){
        static int s_v=1;
        auto int a_v=1;
        register r_v=1;
        volatile v_v=1;
        int *h_v=(int*)malloc(sizeof(int));
        *h_v=1;
        printf("1:g_v=%d,s_v=%d,a_v=%d,r_v=%d,v_v=%d,h_v=%d
    ",g_v,s_v,a_v,r_v,v_v,*h_v );
        printf("setjmp(jmp)=%d
    ",setjmp(jmp));
        if(setjmp(jmp) == 1){
            printf("2:g_v=%d,s_v=%d,a_v=%d,r_v=%d,v_v=%d,h_v=%d
    ",g_v,s_v,a_v,r_v,v_v,*h_v );
            exit(1);
        }
    
        g_v=2;
        s_v=2;
        a_v=2;
        r_v=2;
        v_v=2;
        *h_v=2;
        printf("3:g_v=%d,s_v=%d,a_v=%d,r_v=%d,v_v=%d,h_v=%d
    ",g_v,s_v,a_v,r_v,v_v,*h_v );
        fun();
        return 0;
    
    
    
    }

    [root@centos1 process]# ./a.out
    1:g_v=1,s_v=1,a_v=1,r_v=1,v_v=1,h_v=1
    setjmp(jmp)=0
    3:g_v=2,s_v=2,a_v=2,r_v=2,v_v=2,h_v=2
    jmp=6294496
    2:g_v=2,s_v=2,a_v=1,r_v=1,v_v=2,h_v=2

  • 相关阅读:
    Spring使用c标签时缺失jstl uri="http://java.sun.com/jsp/jstl/core" prefix="c"
    Jsp页面报错:The superclass"javax.servlet.http.HttpServlet" was not found on the Java Build Path错误异常
    [Spring in action 笔记0]没有xml配置的spring
    Java语言和C语言的static的区别以及它们的内存分配方式
    为什么连续的scanf会被跳过或不执行
    scanf("%[^ ]", str)正则用法,strchr()用法
    newInstance参数详解
    多线程之BlockingQueue中 take、offer、put、add的一些比较
    [Struts2 in action 笔记3]坐享其成的拦截器(栈)
    ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath
  • 原文地址:https://www.cnblogs.com/HKUI/p/9311893.html
Copyright © 2020-2023  润新知