《APUE》读书笔记—第七章进程环境

  本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制。

  main函数的原型为int main(int argc,char *argv[]);其中argc是命令行参数的数目,argv是指向参数的各个指针构成的数组。当内核执行C程序时,使用一个exec函数,在调用main函数前线调用一个特殊的启动例程,从内核获取命令行参数和环境变量。

  进程终止分为正常终止和异常终止。正常终止包括:(1)从main返回,(2)调用exit();(3)调用_exit或者_Exit();(4)最后启动一个线程从其启动例程返回;(5)最后一个线程调用pthread_exit。异常终止包括:(1)调用abort();(2)接收到一个信号并终止;(3)最后一个线程对取消请求做出响应。

1、exit函数系列:_exit和_Exit函数立即进入内核,而exit函数则执行清理处理(如关闭标准I/O流,执行各终止处理程序)。在main函数执行return (0)与exit(0)是等价的。

#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void exit(int status);
void _Exit(int status);

 2、atexit函数,用来登记终止处理程序,一个进程可以登记多达32个函数,这些函数将有exit自动调用,调用顺序与登记顺序相反,同一个函数可以登记多次,则也会被调用多次。函数原型如下:

#include <stdlib.h>
int atexit(void (*function)(void));  //成功返回0,否则返回非0值

一个C程序启动和终止的过程如下图所示:

 

内核使程序执行的唯一方法是调用一个exec函数,终止的唯一方法是显式或者隐式地通过exit函数调用_exit()或_Exit(),也可以非自愿的由一个信号使其终止。

写个程序进程练习,程序如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 void exit_func1();
 5 void exit_func2();
 6
 7 int main()
 8 {
 9     //登记终止处理函数
10     atexit(exit_func2);
11     atexit(exit_func1);
12     atexit(exit_func2);
13     printf("Test exit and atexit.\n");
14     exit(0);
15 }
16
17 void exit_func1()
18 {
19     printf("exit_func1() is called.\n");
20 }
21 void exit_func2()
22 {
23     printf("exit_func2() is called.\n");
24 }

程序执行结果如下:

  命令行参数,当执行一个程序时,调用exec的进程可将命令行参数传递给该新程序,进程间通信数据传输进程用到。写个程序输出其命令行参数,程序如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 int main(int argc,char *argv[])
 5 {
 6     int i;
 7     for(i=0;i<argc;++i)
 8         printf("argv[%d]: %s\n",i,argv[i]);
 9     exit(0);
10 }

测试结果如下:

C程序的存储空间布局:

存储器分配函数:

#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nmemb,size_t size);
void *realloc(void *ptr, size_t size); //更改以前分配区的长度

void free(void *ptr);

写个程序练习函数的使用:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4
 5 int main()
 6 {
 7     int n;
 8     int *pData;
 9     printf("Enter the number: ");
10     scanf("%d",&n);
11     pData = (int*)malloc(sizeof(int)*n);
12     memset(pData,0,sizeof(int)*n);
13     printf("pData address is :%p\n",pData);
14     free(pData);
15     pData = (int*)calloc(n,sizeof(int));
16     printf("pData address is :%p\n",pData);
17     pData=realloc(pData,sizeof(int)*(n+10));
18     printf("pData address is :%p\n",pData);
19     free(pData);
20     exit(0);
21 }

 

环境变量:形式为name=value,环境变量可以在用进程进程间通信,exec函数可以通过环境变量进程传参数,例如在CGI程序中用到HTTP协议get和post方法对应的环境变量。环境变量可用于所有的子进程,这包括编辑器、脚本和应用。环境变量操作函数如下:

#include <stdlib.h>
char *getenv(const char *name); //指向与name关联的value的指针
int putenv(char *string);  //取形式为name=value的字符串,将其放到环境表中
int setenv(const char *name, const char *value, int overwrite); //将name设置为value
int unsetenv(const char *name);  //删除name的定义

int clearenv(void); //删除环境表中所有项

写个程序进行环境变量的读取设置及删除。程序如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4
 5 int main()
 6 {
 7     char *name;
 8     char *value;
 9     char *str = "LENGTH=10";
10     char *pvalue;
11     name = "QUERY";
12     value = "Hello,world";
13     //设置环境变量,1表示若那么存在,则先先删除
14     setenv(name,value,1);
15     //用字符串设置环境变量
16     putenv(str);
17     //取环境变量的值
18     pvalue = getenv(name);
19     printf("%s=%s\n",name,pvalue);
20     pvalue = getenv("LENGTH");
21     printf("LENGTH=%s\n",pvalue);
22     unsetenv("LENGTH");
23     //取系统HOME环境变量的值
24     pvalue = getenv("HOME");
25     printf("HOME=%s\N",pvalue);
26     exit(0);
27 }

 程序执行结果如下:

全局跳转函数setjmp和longjmp:解决跨越函数跳跃,处理发生在深层次嵌套函数调用中出错情况非常有用。全局或者静态变量的值在执行longjmp是保持不变。函数原型如下:

int clearenv(void);
#include <setjmp.h>
int setjmp(jmp_buf env);  //返回值为0为直接调用,从longjmp调用返回非0值
int sigsetjmp(sigjmp_buf env, int savesigs);

  一般用法是:设置一个全局的jmp_buf变量,在主进程中调用setjmp()设置跳转变量,如果后面的函数出现错误,调用longjmp设置一个值,说明函数调用出错。写个程序来表达用法,程序如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <setjmp.h>
 5
 6 void func1();
 7 void func2();
 8 void func3();
 9 //定义一个全局的跳转变量
10 jmp_buf jmpbuffer;
11
12 int main()
13 {
14     int ret;
15     //获取返回值,0为直接调用
16     ret=setjmp(jmpbuffer);
17     switch(ret)
18     {
19     case 1:
20         printf("func1 is error.\n");
21         exit(-1);
22     case 2:
23         printf("func2 is error.\n");
24         exit(-1);
25     case 3:
26         printf("func3 is error.\n");
27         exit(-1);
28     }
29     func1();
30     exit(0);
31 }
32 void func1()
33 {
34     //longjmp(jmpbuffer,1);
35     func2();
36 }
37 void func2()
38 {
39     //longjmp(jmpbuffer,2);
40     func3();
41 }
42 void func3()
43 {
44     //设置跳转
45     longjmp(jmpbuffer,3);
46 }

程序执行结果如下:

进程资源限制函数:getrlimit和setrlimit,资源结果和函数原型如下:

struct rlimit {
    rlim_t rlim_cur;  /* Soft limit */
    rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */
};

#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);

关于进程资源限制目前还不知道有何用,以后再来补充。

时间: 2024-12-29 11:25:11

《APUE》读书笔记—第七章进程环境的相关文章

MYSQL必知必会读书笔记第七章之数据过滤_Mysql

mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 计算次序: where 可以包含任意数目的and和or,允许两者结合以进行复杂和高级的过滤.但是SQL在操作or之前会优先的处理AND操作符.如果想优先的使用or的条件可以使用括号. in:为什么要使用in操作符?其优点具体如下. 1.在使用长的合法选项清单时,in操作符的语法更清楚直观 2.在使用IN时,计算的次序更容易管理

Android群英传笔记——第七章:Android动画机制和使用技巧

Android群英传笔记--第七章:Android动画机制和使用技巧 想来,最 近忙的不可开交,都把看书给冷落了,还有好几本没有看完呢,速度得加快了 今天看了第七章,Android动画效果一直是人家中十分重要的一部分,从早期的Android版本中,由于动画机制和绘图机制的不健全,Android的人机交互备受诟病,Android从4.X开始,特别是5.X,动画越来越完善了,Google也开始重视这一方面了,我们本章学习的主要内容有 Android视图动画' Android属性动画 Android动

MYSQL必知必会读书笔记第三章之显示数据库_Mysql

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. show column from tablename: 对每一个字段返回一行,行中包含字段名,数据类型.是否允许NULL.键信息.默认值以及其他信息. describe 语句: MySQL支持使用describ作为show columns from 的一种快捷方式.describ tablename 所支持的其他的show语句: show s

MYSQL必知必会读书笔记第六章之过滤数据_Mysql

mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. where子句的位置,在同时使用ORDER BY 和WHERE子句时应该让ORDER BY 位于where之后,否则会产生错误. 1.不匹配检查 复制代码 代码如下: SELECT vend_id FROM products where vend_id <>1003 等同于 复制代码 代码如下: SELECT vend_id

《APUE》读书笔记—第十一章线程

一个进程在同一时刻只能做一件事情,线程可以把程序设计成在同一时刻能够做多件事情,每个线程处理各自独立的任务.线程包括了表示进程内执行环境必需的信息,包括进程中标识线程的线程ID.一组寄存器值.栈.调度优先级和策略.信号屏蔽字.errno变量以及线程似有数据.进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本.程序的全局内存.栈及文件描述符. 使用线程的好处:(1)为每种事件分配单独的线程.能够简化处理异步事件的代码:(2)多个线程自动地可以访问相同的存储地址空间和文件描述符:(3)

MYSQL必知必会读书笔记第四章之检索数据_Mysql

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 使用Select语句返回的数据,可能会发现显示的数据会与其他的地方顺序不同.出现这种情况很正常.如果没有明确排序查询结果.则返回的数据没有特殊意义.返回数据的顺序可能是是数据被添加到表中的顺序,也可能不是.只要返回相同数目的行,就是正常. 注意:SQL语句和大小写 请注意,SQL语句不区分大小写,因此select和SELECT是相同的.同样,

【PMP】Head First PMP 学习笔记 第七章 成本管理

第七章 成本管理 所有的项目归根结底都是为了钱. 举例的实际问题:开一家酒吧分店,预算只有1w刀 -> 建立一个预算,并且随着项目进行,不断将项目进展与预算进行比较. 成本管理过程 估算成本过程 确定预算过程 控制成本过程 估算成本过程 输入工具输出 输入 项目进度 人力资源计划 组织过程资产 企业环境要素 风险登记表更新 范围基线 工具和技术 项目管理估算软件 供应商投标分析 储备分析 质量成本 质量成本就是正确完成项目所花的钱. 输出 活动成本估算 成本估算基础 项目文档更新 请求的变更 数

《APUE》读书笔记-第十七章高级进程间通信

本章主要介绍了基于STREAM的管道和UNIX域套接字,这些IPC可以在进程间传送打开文件描述符.服务进程可以使用它们的打开文件描述符与指定的名字相关联,客户进程可以使用这些名字与服务器进程通信. 1.基于STREAMS的管道 STREAMS pipe是一个双向(全双工)管道,单个STREAMS管道就能向父.子进程提供双向的数据流.如下图所示: 下面采用STREAMS管道实现加法协同进程实例,程序如下: View Code 1 1 #include <stdio.h> 2 2 #include

《APUE》读书笔记—第四章文件和目录

本章主要介绍的是文件结构及目录.重点是通过stat函数获取文件的结构信息,然后是文件目录及其遍历.学完本章后,编写了一个输出给的目录下的文件信息的程序. 首先是包含在<sys/stat.h>文件下的stat.fstat.lstat三个函数,三个函数的原型如下: int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct