zoukankan      html  css  js  c++  java
  • C7 : 进程环境



    1. 引言

    1:程序执行时,main是如何被调用的

    2:命令行参数如何传递给新程序

    3:典型的存储空间布局样式

    4:如何分配额外的储存空间

    5:进程如何使用环境变量

    6:进程的不同终止方式

    7longjmpsetjmp函数以及它们和栈的交互方式

    8:进程的资源限制

    2.main函数

    main函数的原型是int main(int argc, char* argv[]);

    内核执行c程序的步骤

    内核调用一个启动例程

    可执行程序文件将此启动例程指定为程序的起始地址

    启动例程从内核获取命令行参数和环境变量参数

    运行可执行文件

    3.进程终止

    5种正常终止方式

    1、从main函数返回

    2、调用exit

    • void exit (int __status)

    • int atexit (void (*__func) (void))

    • exit返回时会调用atexit或者on_exit注册的回调函数

    • 执行一些清理动作后返回到内核

    执行标准io库的清理关闭操作,对于所有打开的流调用fclose

    3、调用_exit_Exit

    • void _Exit (int __status)

    • _Exit返回时不调用atexit注册的回调函数

    • 立即返回到内核,不清理

    二者的区别

     

    4、最后一个线程从启动例程中返回

    5、从最后一个线程调用pthread_exit

    3种异常终止

    调用abort

    接收到一个signal

    最后一个线程对取消请求的响应

    程序的启动和终止

     

    4.命令行参数

    argc

    argv

    ISO CPOSIX都要求argv[argc]null

    5.环境表

    extern char** environ;

    字符指针数组

     

    6. 存储空间布局

    正文段

    CPU执行的指令部分

    • 通常为只读,防止程序意外修改指令
    • int a = 10;
    • 存放程序中已初始化的全局变量(包含静态变量)的一块内存区域
    • const char* a = "abc";

    初始化数据段

    程序中需要明确付初值的变量

    可分为read write区域和read only区域

    • "abc"read only区域

    • aread write区域

    未初始化数据段,bssblock started by symbol

    long sum[1000];

    存放程序中未初始化的全局变量(静态变量)的一块内存区域

    自动变量以及函数调用需要保存的信息

    • 最近被调用的函数都会在栈上为其自动和临时分配存储空间
    • 递归函数调用自身时,生成一个新的栈帧。因此,一次函数的调用实例不会影响下一次

    堆中进行动态内存分配

    典型的存储器排列

     

    测试案例:https://www.geeksforgeeks.org/memory-layout-of-c-program/

    高地址顶部:命令行参数和环境变量

    • 程序启动时,由内核获取

    7.共享库

    8.存储空间分配

    malloc

    void *malloc (size_t __size)

    分配指定长度的存储区,初始值不确定

    calloc

    void *calloc (size_t __nmemb, size_t __size)

    分配指定长度的存储区,且每一位都初始化为0

    realloc

    void *realloc (void *__ptr, size_t __size)

    增加或减少之前的分配区,可能需要将之前分配的内容移动到另一个足够大的区域。新增区域的初始值不确定

    以上三个分配函数的指针一定是适当对齐的,可适用于任何数据对象

    free

    void free (void *__ptr)

    9.环境变量

    getenv

    char *getenv (const char *__name)

    putenv

    int putenv (char *__string)

    形式为name=value的字符串,覆盖已有名称的name

    setenv

    int setenv (const char *__name, const char *__value, int __replace)

    设置namevalue,如果name存在,且replace0,则替换现有定义

    unsetenv

    int unsetenv (const char *__name)

    删除当前的name

    环境表位于存储空间的顶部,下面就是栈区

     

    修改name对于的value

    • 如果长度小于等于原value的长度,则覆盖原value即可
    • 如果长度大于原value的长度,则malloc后重新传递指针给name
    • 没看明白

    增加新的name

     

    10. setjmplongjmp

    函数的调用栈

    这俩函数用于实现函数栈帧之间的跳转

    setjmp

    • int _setjmp (struct __jmp_buf_tag __env[1])

    返回0表示直接调用

    返回非0,表示longjmp的跳转后的结果

    • 将当前setjmp所在行的栈帧的信息存储在jmp_buf

     

    longjmp

    • void longjmp (struct __jmp_buf_tag __env[1], int __val)
    • 需要跳转的地方执行longjmp

    第一个参数是setjmp缓存的jmpbuf

    第二个参数是跳转到setjmp后,setjmp的返回结果

    longjmp之后的问题

    1.自动变量、寄存器变量、易失变量volatile

    • longjmp之后,这些变量的值不确定

    不进行任何优化时,自动变量、全局变量、静态变量、寄存器变量、volatile变量都不会改变

    优化后,全局变量、static变量、volatile变量不会改变,而其他变量可以改变

    • volatile关键字

    • 1:编译器不知道多线程访问的变量特征,不知情哪些变量是在别的线程中修改的

    • 2:程序运行过程中,变量会被存储到寄存器的值,而寄存器内的值不会被中断(外部改变变量)影响

    • 3:编译器优化,通常,只知晓当前线程的操作,对变量的访问判断仅进行一次读取,后续访问均从寄存器获得。尽管外部线程对该变量进行了改写,当前线程依旧使用当前线程的寄存器(旧的值)

    • 4:加上volatile关键字后,编译器不会再对该变量进行任何优化。访问时,会从变量地址处重新获取数据

    举例:signal是外部变量,多线程共享

     

    编译器优化的,在初始赋值后,ax不会再有任何改变

     

    这是加上volatile关键字后,循环内部每次访问到ax,则重新读取

     

    11.进程的资源限制

    getrlimit

    int getrlimit (__rlimit_resource_t __resource,      struct rlimit *__rlimits)

    setrlimit

    int setrlimit (__rlimit_resource_t __resource,      const struct rlimit *__rlimits)

    资源限制,软限制和硬限制(软限制的最大值)

  • 相关阅读:
    爱你就是我的幸福
    科学加艺术 85句管理名言
    转:IPV6及在UBUNTU和windows下的安装
    JXSE是否可以实现非阻塞IO?
    Transmitting and Receiving RTP over Custom Transport Layer
    多显示器
    可靠的双向管道和不可靠的双向管道
    the source for JMStudio
    转:浅析 Java Thread.join()
    Building Scalable and High Efficient Java Multimedia Collaboration
  • 原文地址:https://www.cnblogs.com/hgwang/p/14761084.html
Copyright © 2011-2022 走看看