Unix环境编程之 进程环境

前端之家收集整理的这篇文章主要介绍了Unix环境编程之 进程环境前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

(1)当执行程序时,main函数是的如何调用

main函数原型是

  1. int main(int argc,char *argv[]);
  2. argc是命令行参数,argv是指向参数的各个指针的数组。
  3.  
  4. #include"apue.h"
  5.  
  6. int main()
  7. {
  8. int i;
  9. for(i=0;i<argc;i++)
  10. {
  11. printf("argv[%d]:%s\n",i,argv[i]);
  12. exit(0);
  13. }
  14. //编译运行后如下:
  15. zsj@zsj-virtual-machine:~/ccode$ cc -o 7-3 7-3.c
  16. zsj@zsj-virtual-machine:~/ccode$ ./7-3 arg1 TEST foo
  17. argv[0]:./7-3 //第一个指针指向文件
  18. argv[1]:arg1
  19. argv[2]:TEST
  20. argv[3]:foo

内核执行c程序时(使用exec函数调用main之前先调用一个特殊例程。例程从内核取得命令行参数 和环境变量值。

(2)各种不同的进程终止方式

  1. #include<stdlib.h>
  2. void exit(int status);
  3. void_Exit(int status);
  4.  
  5. #include<unistd.h>
  6. void _exit(int status);

这三个函数都可以用来正常终止一个程序:_exit 和_Exit立即进入内核,exit则执行一些清理操作(调用执行各终止处理程序,关闭所有标准I/O流)

@H_301_86@三个函数都带一个整型参数称为终止状态。
(a)调用这些函数时不带终止状态.
(b)main执行了一个无返回值的return语句
(c)main没有声明返回值是整型的。
以上三种情况 终止状态是未定义的。

(3)c程序的存储空间布局

text:正文段。这是由cpu执行的机器指令部分,正文段是可共享的,正文段常常是只读的。

初始化数据段。出现在任何函数以外的声明。

非初始化数据段。开始执行程序之前内核将此段中的数据初始化为0或空指针。

栈:自动变量以及每次函数调用时所保存的信息都放在栈中。递归函数每次调用自身都使用一个新的栈帧

堆:通常在堆中进行动态存储分配。

(4)如何分配存储空间

  1. #include<stdlib.h>
  2. void *malloc(size_t size);
  3. void *calloc(size_t nobj,size_t size);//为指定数量具有指定长度的对象分配存储空间。
  4. void *realloc(void *ptr,size_t newsize);
  5.  
  6. void free(*ptr);
  7.  
  8. 三个函数返回值,若成功则返回非空指针,出错则返回null

(5)创建进程以及进程属性

进程标识符

@H_301_86@每个进程都有一个非负整数表示的唯一进程ID。进程ID可以重用,当一个进程终止时,进程ID就可以重新使用了。
系统中有一些专用的进程 ID为0的表示 调度进程,被称为交换进程。并不执行磁盘上的任何程序。
ID为1的是init进程,它通常读与系统初始化有关的文件

fork函数

  1. #include<unistd.h>
  2. pid_t fork(void)
  3.  
  4. 返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1
@H_301_86@由fork创建的新进程称为子进程。fork函数调用一次,但返回两次。
父进程返回新进程ID,新进程返回0。

@H_301_86@子进程和父进程继续执行fork()之后的指令。子进程是父进程的副本。获得父进程的数据空间、堆栈、父子进程并不共享这些存储部分。父子进程共享正文段。

  1. #include<stdio.h>
  2. #include"apue.h"
  3. #include<myerror.h>
  4.  
  5.  
  6. int glob=6;
  7. char buf[]="a write to stdout\n";
  8. int main(void)
  9. {
  10. int var;
  11. pid_t pid;
  12.  
  13. var=88;
  14.  
  15. if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)
  16. err_sys("write error");
  17. printf("before fork\n");
  18. if(pid=fork()<0)
  19. {
  20. err_sys("fork error");
  21.  
  22. }
  23.  
  24. else if(pid==0)
  25. {
  26. glob++;
  27. var++;
  28. }
  29. else{
  30.  
  31. sleep(2);
  32.  
  33. }
  34.  
  35. printf("pid= %d,glob=%d,var=%d\n",getpid(),glob,var);
  36.  
  37. exit(0);
  38.  
  39.  
  40. }
  41.  
  42. zsj@zsj-virtual-machine:~/ccode$ cc 8-1.c
  43. zsj@zsj-virtual-machine:~/ccode$ ./a.out
  44. a write to stdout
  45. before fork
  46. pid=14828,glob=7,var=89 //子进程的变量变了
  47. pid=14827,glob=6,var=88 //父进程得变量值没变
  48. zsj@zsj-virtual-machine:~/ccode$ ./a.out >temp.out
  49. zsj@zsj-virtual-machine:~/ccode$ cat temp.out
  50. a write to stdout
  51. before fork
  52. pid=14830,var=89
  53. before fork
  54. pid=14829,var=88
  55. zsj@zsj-virtual-machine:~/ccode$

在fork之后 是父进程还是子进程先执行时不确定的。这取决于内核所使用的调度算法。如果要求父子进程之间相互同步,则要求某种形式的进程间通信。

父进程使自己休眠两秒,以使子进程先执行。

write函数是不带缓冲的。因为在fork之前调用write,所以其数据写到标准输出一次,

但是标准库是带缓冲的.

如果标准输出连到终端设备,则它是行缓冲的,否则它是全缓冲的。

当以交互运行该程序时,只得到printf一行,原因是标准输出的缓冲区由换行符冲洗。而将标准输出重定向到一个文件时,却得到printf输出两行,其原因是,在fork之前调用了printf一次,但当调用fork时,该行数据仍在缓冲区中,然后在父进程数据空间被复制到子进程中,当每个进程终止时,最终会冲洗缓冲区中的副本。

猜你在找的Bash相关文章