`

UNIX环境高级编程 进程环境

 
阅读更多

 

 

相关函数列表

//退出函数
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);

//按照ISO C的规定,一个进程可以登记多至32个函数,这些函数将由exit自动
//调用。我们称这些函数为终止处理程序(exit handler),并调用atexit函数来
//登记这些函数,这个函数起始就是注册退出钩子函数,退出程序时执行一些自定义的函数
//执行的顺序和注册的顺序正好相关,相同的函数可以注册多次
#include <stdlib.h>
int atexit(void (*func)(void));

//环境表
int main(int argc, char *argv[], char *envp[]);

//动态分配空间的函数
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
void free(void *ptr);


//获取环境变量值
#include <stdlib.h>
char *getenv(const char *name);

//putenv设置name=value
//setenv将name设置为value,如果rewrite非0则先删除之前的定义否则不删
//unsetenv删除name定义
#include <stdlib.h>
int putenv(char *str);
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);


//C语言中goto是不能跨越函数的,而执行这种功能是由setjmp和longjmp完成
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);


//每个进程都有一组资源限制,可以用下列函数设置和获取
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlptr);
int setrlimit(int resource, const struct rlimit *rlptr);

//rlimit结构体如下
struct rlimit {
    rlim_t rlim_cur;    //soft limit
    rlim_t rlim_max;    //hard limit
};

 

 

进程终止,有8种方式,其中5钟是正常终止

1) 从main返回

2) 调用exit

3) 调用_exit或_Exit

4) 最后一个现场从其启动列程返回

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

异常终止

1) 调用abort

2) 接到一个信号

3) 最后一个线程对取消请求作出响应

 

1999 ISO C扩展要求编译器要求main必须声明为返回整型

当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行文件将此例程指定为程序的起始地址--这是由连接编辑器设置的,而连接编辑器则由C编译器调用。启动例程从内核取得命令行参数和环境变量值,然后喂按上述方式调用main函数做好安排。

一个C程序是如何启动和终止的


 

函数sbrk()用来实现系统扩充(或缩小)进程的堆

但是大多数malloc和free的实现都不见效进程的存储空间,释放的空间可供以后再分配,但将它们保持在

malloc池中而不繁华给内核。

大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息--分配块的长度,指向

下一个分配块的指针等。这就意味着如果超过一个已分配区的尾端或者在已分配区起始位置之前进行写操作,则会改写另一块管理记录信息。这种类型的错误是在灾难性的单不会很快暴露出来。

 

 

替代的存储空间分配程序

1) libmalloc

2) vmalloc

3) quick-fit

4) jemalloc

5) TCMalloc

6) 函数alloca

 

Single UNIX Specification定义的环境变量

变量 说明
COLUMNS 终端宽度
DATEMSK getdate模板文件路径名
HOME home起始目录
LANG 本地名
LC_ALL 本地名
LC_COLLATE 本地排序名
LC_CTYPE 本地字符分类名
LC_MESSAGES 本地消息名
LC_MONETARY 本地货币编辑名
LC_NUMERIC 本地数字编辑名
LC_TIME 本地日期/时间格式名
LINES 终端高度
LOGNAME 登陆名
MSGVERB fmtmsg处理的消息组成部分
NLSPATH 消息类模板序列
PATH 搜索可执行文件的路径前缀列表
PWD 当前工作目录的绝对路径名
SHELL 用户首选的shell名
TERM 终端类型
TMPDIR 在其中创建临时文件的目录路径名
TZ 时区信息

 

 

在更改资源限制时,必须遵守下列三条规则(使用ulimit命令获取和设置)

1) 任何一个进程都可将一个软限制值更改为小于或等于其硬限制值

2) 任何一个进程都可降低其硬限制值,但它必须大于或等于其软限制值,这种降低对普通用户是不可逆的

3) 只有超级用户进程可以提高硬限制值

限制 说明
RLIMIT_AS 进程总的可用存储空间的最大长度(字节),这影响到sbrk函数和mmap函数
RLIMIT_CORE core文件的最大字节数,若其值为0则组织创建core文件
RLIMIT_CPU CPU时间的最大量值(秒),当超过此软限制时,向该进程发送SIGXCPU信号
RLIMIT_DATA 数据段的最大字节长度
RLIMIT_FSIZE 可以创建的文件的最大字节长度,当超过此软限制时,则向该进程发送SIGXFSZ信号
RLIMIT_MEMLOCK 一个进程使用mlock能够锁定在存储空间中的最大字节长度
RLIMIT_MSGQUEUE 进程为POSIX消息队列可分配的最大存储字节数
RLIMIT_NICE 为了影响进程的调度优先级,nice值可设置的最大限制
RLIMIT_NOFILE

每个进程能打开的最多文件数,更改此限制将影响到sysconf函数在参数

_SC_OPEN_MAX中的返回值

RLIMIT_NPROC

每个实际用户ID可拥有的最大子进程数,更改此限制将影响到sysconf函数在参数

_SC_CHILD_MAXZ中的返回值

RLIMIT_NPTS 用户可用时打开的伪终端的最大数量
RLIMIT_RSS

最大驻内存集字节长度(resident set size in bytes RSS)如果可用的物理存储器非常

少,则内核将从进程处取回超过RSS的部分

RLIMIT_SBSIZE 在任意给定时刻,一个用户可以占用的套接字缓冲区的最大长度(字节)
RLIMIT_SIGPENDING 一个进程可排队的信号最大数量,这个限制是sigqueue函数实施的
RLIMIT_STACK 栈的最大字节长度
RLIMIT_SWAP 用户可消耗的交换空间的最大字节数
RLIMIT_VMEM 这是RLIMIT_AS的同义词
RLIMIT_INFINITY 指定了一个无限量的限制

 

 

 

atexit函数使用过程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static void my_exit1(void) {
        printf("first exit handler\n");
}

static void my_exit2(void) {
        printf("second exit handler\n");
}

int main(int argc, char *argv[]) {
        if(atexit(my_exit2) != 0) {
                printf("can't register my_exit2");
        }
        if(atexit(my_exit1) != 0) {
                printf("can't register my_exit1");
        }
        if(atexit(my_exit1) != 0) {
                printf("can't register my_exit1");
        }
        printf("main is done\n");
        return 0;
}

 

 

gcc关闭共享库

gcc -static hello.c
关闭后可以发现目标文件明显比之前大了很多

 

 

 

假设一个函数程序如下

这个程序调用顺序是main --> do_line --> cmd_add --> get_token

如果在get_token()函数中发生了错误,函数需要跳回main中,此时我们不得不坚持返回值然后一个个返回

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#define TOK_ADD 5
#define MAXLINE 1024
char *tok_ptr;

int get_token(void) {
        //fetch next token from line pointed to by tok_ptr
}

void cmd_add(void) {
        int token;
        token = get_token();
        //rest of processing for this command
}

void do_line(char *ptr) {
        int cmd;
        tok_ptr = ptr;
        while((cmd=get_token()) > 0) {
                switch(cmd) {
                        case TOK_ADD:
                            cmd_add();
                            break;
                }
        }
}


int main(int argc, char *argv[]) {
        char line[MAXLINE];
        if(fgets(line,MAXLINE,stdin) != NULL) {
                do_line(line);
        }

        return 0;
}

 

用setjmp和longjmp函数可以跳过函数返回

这里需要定义个全局的jmp_buf结构体,也就是setjmp()函数的env

longjmp可以对应多个setjmp()函数,通过第二个参数val区分,比如cmd_add对应1,而get_token对应2

这样就可以知道是哪个函数返回的了

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#define TOK_ADD 5
#define MAXLINE 1024
char *tok_ptr;
jmp_buf jmpbuffer;

int get_token(void) {
        //fetch next token from line pointed to by tok_ptr
}

void cmd_add(void) {
        int token;
        token = get_token();
        if(token < 0) {
                longjmp(jmpbuffer,1);
        }
}

void do_line(char *ptr) {
        int cmd;
        tok_ptr = ptr;
        while((cmd=get_token()) > 0) {
                switch(cmd) {
                        case TOK_ADD:
                            cmd_add();
                            break;
                }
        }
}

int main(int argc, char *argv[]) {
        char line[MAXLINE];
        if(setjmp(jmpbuffer) != 0) {
                printf("setjmp error\r\n");
        }
        if(fgets(line,MAXLINE,stdin) != NULL) {
                do_line(line);
        }

        return 0;
}

 

 

执行跳转后各种类型的变量情况

自动,静态,寄存器,全局,易变 的变量是否会随着函数的回滚而回滚

目前测试是不会,所有变量都没有回滚,书中说到对于全部优化情况下,寄存器变量,易变变量会回滚

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

static jmp_buf jmpbuffer;
static int globval;

static void f2(void) {
        longjmp(jmpbuffer, 1);
}

static void f1(int i, int j, int k, int m) {
        printf("int f1()\n");
        printf("globval=%d, atuoval=%d, regival=%d, valaval=%d, statval=%d\n",globval,i,j,k,m);
}

int main(int argc, char *argv[]) {
        int autoval;
        register int regival;
        volatile int volaval;
        static int statval;

        globval = 1;
        autoval = 2;
        regival = 3;
        volaval = 4;
        statval = 5;

        if(setjmp(jmpbuffer) != 0) {
                printf("after jmp\n");
                printf("globval=%d, atuoval=%d, regival=%d, valaval=%d, statval=%d\n",globval,autoval,regival,volaval,statval);
                exit(0);
        }
        globval = 95;
        autoval = 96;
        regival = 97;
        volaval = 98;
        statval = 99;
        f1(autoval, regival, volaval, statval);
        exit(0);
}

 

 

自动变量需要注意返回值

这里的函数open_data返回值的内容是当前函数栈中的,所以返回了就没有了,应当定义成静态的或者通过

malloc函数动态申请的

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#define BUFSIZE 1024
FILE *open_data(void) {
        FILE *fp;
        char databuf[BUFSIZE];
        if((fp=fopen("datafile","r")) == NULL) {
                return(NULL);
        }
        if(setvbuf(fp,databuf,_IOLBF,BUFSIZE) != 0) {
                return (NULL);
        }
        return fp;
}

int main(int argc, char *argv[]) {
        FILE *fp = open_data();
}

 

 

获取当前系统的各种软限制和硬限制

#include <stdio.h>
#include <sys/resource.h>
#define doit(name) pr_limits(#name, name);

static void pr_limits(char *name, int resource) {
        struct rlimit limit;
        unsigned long long lim;
        if(getrlimit(resource, &limit) < 0) {
                printf("getrlimit error for %s,",name);
        }
        printf("%-14s  ",name);

        if(limit.rlim_cur == RLIM_INFINITY) {
                printf(" (infinite) ");
        } else {
                printf("%10lld ",lim);
        }

        if(limit.rlim_max == RLIM_INFINITY) {
                printf(" (infinite) ");
        } else {
                printf("%10lld",lim);
        }
        putchar((int)'\n');
}

int main(int argc, char *argv[]) {
#ifdef RLIMIT_AS
        doit(RLIMIT_AS);
#endif

        doit(RLIMIT_CORE);
        doit(RLIMIT_CPU);
        doit(RLIMIT_DATA);
        doit(RLIMIT_FSIZE);

#ifdef  RLIMIT_MEMLOCK
        doit(RLIMIT_MEMLOCK);
#endif

#ifdef RLIMIT_MSGQUEUE
        doit(RLIMIT_MSGQUEUE);
#endif

#ifdef RLIMIT_NICE
        doit(RLIMIT_NICE);
#endif

        doit(RLIMIT_NOFILE);

#ifdef RLIMIT_nproc
        doit(RLIMIT_NPROC);
#endif

#ifdef RLIMIT_RSS
        doit(RLIMIT_RSS);
#endif

#ifdef RLIMIT_SBSIZE
        doit(RLIMIT_SBSIZE);
#endif

#ifdef RLIMIT_SIGPENDING
        doit(RLIMIT_SIGPENDING);
#endif

        doit(RLIMIT_STACK);

#ifdef RLIMIT_SWAP
        doit(RLIMIT_SWAP);
#endif

#ifdef RLIMIT_VMEM
        doit(RLIMIT_VMEM);
#endif
        return 0;
}

 

 

 

参考

Linux下C程序进程地址空间布局

gcc 编译共享库

c程序是如何启动和终止

 

 

 

 

 

 

  • 大小: 63.6 KB
分享到:
评论

相关推荐

    UNIX环境高级编程-pdf

    此外,书中还涉及了进程环境、系统调用接口、编译和链接、动态装载、错误处理和调试技巧等内容,这些都是在UNIX环境下进行高级编程所必备的知识。同时,书中也讨论了线程编程,包括线程的创建、同步和通信,这对于多...

    UNIX环境高级编程

    《UNIX环境高级编程》是一本深入探讨UNIX系统编程的权威参考书籍。它涵盖了UNIX编程的各个方面,从基础的UNIX系统结构和原理,到文件操作、进程控制、进程间通信、多线程编程、网络编程以及终端I/O和伪终端等内容。...

    UNIX环境高级编程.pdf

    ### UNIX环境高级编程知识点概述 #### 一、UNIX基础知识 **1.1 引言** 在计算机科学领域,操作系统作为连接硬件与软件的桥梁,为应用程序提供了必要的服务,包括但不限于执行新程序、打开文件、读取文件内容、...

    Unix环境高级编程中英文版包括源代码

    《Unix环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,主要涵盖了在Unix操作系统环境下进行高级编程的各种技术和方法。这本书分为多个章节,详细讲解了Unix系统接口、进程管理、文件系统、网络通信等...

    UNIX环境高级编程(PDF超清版)

    《UNIX环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,主要涵盖了在UNIX操作系统上进行高级编程的各种技术和实践。这本书以清晰的结构和深入的解释,为读者提供了丰富的UNIX编程知识,帮助他们掌握在这...

    UNIX环境高级编程(中文第三版)高清完整

    《UNIX环境高级编程(第3版)》在保持前一版风格的基础上,根据最新的标准对内容进行了修订和增补,反映了最新的技术发展。书中除了介绍UNIX文件和目录、标准I/O库、系统数据文件和信息、进程环境、进程控制、进程关系...

    UNIX环境高级编程课后习题详细解答

    "UNIX环境高级编程"通常涵盖的主题包括进程管理、文件I/O、信号处理、网络编程、系统调用接口以及内存管理等。 课后习题往往旨在巩固和深化对这些概念的理解。以下是一些可能涉及的知识点: 1. **进程管理**:包括...

    UNIX环境高级编程(中文版)

    《UNIX环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,它由W. Richard Stevens撰写,对中国乃至全球的UNIX和Linux开发者具有深远影响。这本书深入浅出地讲解了在UNIX系统上进行程序开发的各种技术和...

    Unix环境高级编程_UNIX环境高级编程_

    《Unix环境高级编程》是一本深入探讨Unix操作系统编程的经典之作,由W. Richard Stevens撰写,是许多计算机科学专业学生和专业开发者的必备参考书。这本书详细介绍了如何在Unix系统上进行系统级编程,包括文件I/O、...

    unix环境高级编程 第三版 文字版非扫码(带目录)

    ### Unix环境高级编程 第三版 知识点详解 #### 一、书籍概述与目标读者 《Unix环境高级编程》第三版是一本针对高级程序员和网络专业人士编写的实用参考书。该系列书籍由Addison-Wesley出版社创建于1990年,旨在为...

    unix环境高级编程pdf

    ### Unix环境高级编程知识点概述 #### 一、Unix基础知识概览 **1.1 引言** 本书聚焦于探讨Unix操作系统及其多种版本为程序提供的各项服务。这些服务包括但不限于执行新程序、文件操作(如打开、读取)、内存分配...

    UNIX环境高级编程(中文第三版.zip

    《UNIX环境高级编程》是Unix系统编程领域的一本经典之作,被誉为“圣书”,对于学习Linux开发技术的人员来说,是一本不可或缺的参考书。这本书深入讲解了在Unix环境下进行系统级编程的各种技术和细节,涵盖了从基本...

    UNIX环境高级编程(第三版)-完整目录清晰版

    《UNIX环境高级编程》(第三版) 是一本深入讲解UNIX操作系统编程的经典著作,它由W. Richard Stevens撰写,是IT行业内广泛使用的参考资料。这本书详细介绍了如何在UNIX系统上进行高级程序设计,涵盖了从系统调用、...

    unix环境高级编程1和unix网络编程.进程间通信2.rar

    《Unix环境高级编程》与《Unix网络编程:进程间通信》是两本在计算机科学领域具有深远影响力的经典著作。它们涵盖了Unix系统的核心概念和技术,对于理解操作系统原理、进行系统级编程以及深入研究网络通信有着不可...

    UNIX环境高级编程(清晰PDF中文第一版)

    《UNIX环境高级编程》是一本深受IT专业人士喜爱的经典著作,尤其对于那些致力于深入理解Linux操作系统以及UNIX系统的开发者和系统管理员而言,这本书具有极高的参考价值。作为“学习Linux最好的两本书之一”,它与...

    UNIX环境高级编程(PDF)

    本书的前15章着重于理论知识的阐述,主要内容包括UNIX文件和目录、进程环境、进程控制、 进程间通信以及各种I/O。在此基础上,分别按章介绍了多个应用实例,包括如何创建数据库函数库, PostScript 打印机驱动程序,...

    UNIX环境高级编程 pdf高清版

    《UNIX环境高级编程》是一本被广大程序员和系统管理员视为宝藏的编程指南,其作者W. Richard Stevens在书中展现了深厚的技术功底和对UNIX系统的深刻理解。此书不仅是学习UNIX系统级编程的优秀教材,同时也是深入探索...

    UNIX环境高级编程第二版 中文版 PDF

    - **高级编程技术**:本书重点介绍了Unix/Linux环境下的高级编程技术,包括进程管理、线程控制、网络编程等方面的内容。 #### 3. **关键章节概览** - **进程管理**:详细讲解了如何创建和管理进程,包括进程间的...

Global site tag (gtag.js) - Google Analytics