The Linux Programming Interface 06 Process 进程

本文介绍了Linux编程接口中的进程概念,包括进程的定义、获取PID和PPID的函数、虚拟内存分配、页错误处理、命令行参数和环境变量的使用。还探讨了setjmp和longjmp函数实现的非局部跳转,以及编译优化对程序行为的影响,强调了volatile关键字的作用。
摘要由CSDN通过智能技术生成

The Linux Programming Interface

Process

(01) 进程定义

A process is an abstract entity, defined by the kernel, to which system resources are allocated in order to execute a program.

From the kernel's point of view, a process consists of usr-space memory containing program code and variable used by that code, and a range of kernel data structures that maintain information about the state of the process.

(02) getpid函数

#include <unistd>

pid_t getpid(void);

The getpid() system call returns the process ID of the calling process.

(03) ppid

Each process has a parent - the process that created it. A process can find out the process ID of its parent using the getppid() system call.

pit_t getppid(void);

(04) 进程的内存分配

A virtual memory scheme splits the memory used by each program into small, fixed-size units called pages.
Corresponding, RAM is divided into a series of page frames of the same size.

(05)命中错误

When a process references a page that is not currently resident in physical memory, a page fault occurs, at which point the kernel suspends execution of the process while the page is loaded from disk into memory.

(06)命令行参数

The first argument, int argc, indicates how many command-line arguments there are. The second argument, char *argv[], is an array of pointers to the command-line argumets.

(07)进程的环境变量

Each process has an associated array of strings called the environment list, or simply the environment.

Each of these strings is a definition of the form name = value.

When a new process is created, it inherits a copy of its parent's environment. After the child process has been created, either process may change its own enironment, and these changes are not seen by the other process.

(08) The printenv command displays the current environment list.

也可以使用函数打印所有环境变量

  1 #include "tlpi_hdr.h"
  2 extern char **environ;
  3 
  4 int main(int argc, char *argv[]) {
  5     char **ep;
  6     for (ep = environ; *ep != NULL; ep++)
  7         puts(*ep);
  8 
  9     exit(EXIT_SUCCESS);
 10 }
(09) The getenv() function retrieves individual values from the process environment.

#include <stdlib.h>

char *getenv(const char *name);

(10)The putenv() function adds a new variable to the calling process's environement or midifies the value of an existing variable.

int putenv(char *string);

(11) The setenv() function is an alternative to putenv() for adding a variable to the environment.

int setenv(const char *name, const char *value, int overwrite);

(12) The unsetenv() function removes the variable identified by name from the environment.

int unsetenv(const char *name);

  1 #define _GNU_SOURCE
  2 #include <stdlib.h>
  3 #include "tlpi_hdr.h"
  4 
  5 extern char **environ;
  6 
  7 int main(int argc, char *argv[]) {
  8     int j;
  9     char **ep;
 10     clearenv();     /* Erase entire environment */
 11     for (j = 1; j < argc; j++)
 12         if (putenv(argv[j]) != 0)
 13             errExit("putenv: %s", argv[j]);
 14 
 15     if (setenv("GREET", "Hello world", 0) == -1)
 16         errExit("setenv");
 17     unsetenv("BYE");
 18 
 19     for (ep = environ; *ep != NULL; ep++)
 20         puts(*ep);
 21     exit(EXIT_SUCCESS);
 22 }
 23 
wang@wang:~/test/tlpi-dist/lib$ ./modify_env "GREET=Guten Tag" SHELL=/bin/bash BYE=Ciao
GREET=Guten Tag
SHELL=/bin/bash

(13) goto函数可以完成一个函数内的跳转,setjmp和longjump函数可以在几个函数间跳转。

Calling setjmp() estblishes a target for a later jump performed by longjmp(). This target is exactly the point in the program where the setjmp() call occurred.

举例setjmp从原有的位置执行两遍,第一遍是初始化的值,第二遍是longjmp的第二个参数传回来的值。

  1 #include <setjmp.h>
  2 #include "tlpi_hdr.h"
  3 
  4 static jmp_buf env;
  5 
  6 static void f2(void) {
  7     longjmp(env, 2);
  8 }
  9 
 10 static void f1(int argc) {
 11     if (argc == 1)
 12         longjmp(env, 1);
 13     f2();
 14 }
 15 
 16 int main(int argc, char *argv[]) {
 17     switch(setjmp(env)) {
 18         case 0:     /* This is the return after the initial setjmp() */
 19             printf("Calling f1() after initial setjmp()\n");
 20             f1(argc);   /* Never returns... */
 21             break;      /* ... but this is good form */
 22         case 1:
 23             printf("We jumped back from f1()\n");
 24             break;
 25         case 2:
 26             printf("We jumped back from f2()\n");
 27             break;
 28     }
 29     exit(EXIT_SUCCESS);
 30 }
输出:

wang@wang:~/test/tlpi-dist/lib$ gcc longjmp.c -o longjmp
wang@wang:~/test/tlpi-dist/lib$ ./longjmp
Calling f1() after initial setjmp()
We jumped back from f1()
wang@wang:~/test/tlpi-dist/lib$ ./longjmp x
Calling f1() after initial setjmp()
We jumped back from f2()

(14)优化编译带来的问题,以及volatile关键字的使用

Optimizing compilers may rearrange the order of instruction in a program and store certain variables in CPU registers, rather than RAM.

A demonstration of the interaction of complier optimization and longjmp

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <setjmp.h>
  4 
  5 static jmp_buf env;
  6 
  7 static void doJump(int nvar, int rvar, int vvar) {
  8     printf("Inside doJump(): nvar = %d, rvar = %d vvar = %d\n", nvar, rvar, vvar);
  9     longjmp(env, 1);
 10 }
 11 
 12 int main(int argc, char *argv[]) {
 13     int nvar;
 14     register int rvar;  /* Allocated in register if possible */
 15     volatile int vvar;  /* see text */
 16 
 17     nvar = 111;
 18     rvar = 222;
 19     vvar = 333;
 20 
 21     if (setjmp(env) == 0) { /* Code execute after setjmp() */
 22         nvar = 777;
 23         rvar = 888;
 24         vvar = 999;
 25         doJump(nvar, rvar, vvar);
 26     } else {
 27         printf("After longjmp(): nvar = %d, rvar = %d, vvar = %d\n", nvar, rvar, vvar);
 28     }
 29     exit(EXIT_SUCCESS);
 30 }
输出:

wang@wang:~/test/tlpi-dist/lib$ gcc -o setjmp_vars setjmp_vars.c
wang@wang:~/test/tlpi-dist/lib$ ./setjmp_vars
Inside doJump(): nvar = 777, rvar = 888 vvar = 999
After longjmp(): nvar = 777, rvar = 888, vvar = 999

wang@wang:~/test/tlpi-dist/lib$ gcc -O -o setjmp_vars setjmp_vars.c
wang@wang:~/test/tlpi-dist/lib$ ./setjmp_vars
Inside doJump(): nvar = 777, rvar = 888 vvar = 999
After longjmp(): nvar = 111, rvar = 222, vvar = 999

两种编译条件下显示结果不一样。

Here, we see that after the longjmp(), nvar and rvar have been reset to their values at the time of the setjmp() call. This has occurred because the code reorganization performed by the optimizer has been confused as a consequence of the longjmp().

We can prevent such code reorganization by declaring variables as volatile, which tells the optimizer not to optimize them.

In the preceding program output, we see that varivable vvar, which was declared volatile, was correctly handled, even when we compiled with optimization.

(15) 总结

Each process has a unique process ID and maintains a record of its parent's process ID.

    The virtual memory of a process is logically divided into a number of segments: text, (initialized and uninitialized) data, stack, and heap.

    The stack consists of a series of frames, with a new frame being added as a function is invoked and removed when the function returns. Each frame contains the local variables, function arguments, and call linkage information for a single function invocation.

    The command-line arguments supplied when a program is invoked are made available via the argc and argv arguments to main(). By convention, argv[0] contains the name used to invoke the program.

    Each process receives a copy of its parent's environment list, a set of name-value pairs. The global variable environ and various library functions allow a process to access and modify the variable in its environment list.

    The setjmp() and longjmp() functions provide a way to perform a nonlocal goto from one function to another (unwinding the stack). In order to avoid problems with compiler optimization, we may need to declare variables with the volatile modifier when making use of these functions. Nonlocal gotos can render a program difficult to read and maintain, and should be avoided whenever possible.

(16) 习题

习题6.1

并没有分配内存。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值