Unix环境编程之 进程环境

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

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

main函数原型是

int main(int argc,char *argv[]);
argc是命令行参数,argv是指向参数的各个指针的数组。

#include"apue.h"

int main()
{
int i;
for(i=0;i<argc;i++)
{
    printf("argv[%d]:%s\n",i,argv[i]);
    exit(0);
}
//编译运行后如下:
zsj@zsj-virtual-machine:~/ccode$ cc -o 7-3 7-3.c
zsj@zsj-virtual-machine:~/ccode$ ./7-3 arg1 TEST foo
argv[0]:./7-3 //第一个指针指向文件
argv[1]:arg1   
argv[2]:TEST
argv[3]:foo

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

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

#include<stdlib.h>
void exit(int status);
void_Exit(int status);

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

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

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

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

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

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

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

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

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

(4)如何分配存储空间

#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(*ptr);

三个函数返回值,若成功则返回非空指针,出错则返回null

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

进程标识符

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

fork函数

#include<unistd.h>
pid_t fork(void)

返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1

由fork创建的新进程称为子进程。fork函数调用一次,但返回两次。
父进程返回新进程ID,新进程返回0。

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

#include<stdio.h>
#include"apue.h"
#include<myerror.h>


int glob=6;
char buf[]="a write to stdout\n";
int main(void)
{
 int var;
 pid_t pid;

 var=88;

 if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)
     err_sys("write error");
 printf("before fork\n");
 if(pid=fork()<0)
 {
   err_sys("fork error");

 }

 else if(pid==0)
 {
   glob++;
   var++;
 }
 else{

 sleep(2);

 }

 printf("pid= %d,glob=%d,var=%d\n",getpid(),glob,var);

exit(0);


}

zsj@zsj-virtual-machine:~/ccode$ cc 8-1.c
zsj@zsj-virtual-machine:~/ccode$ ./a.out
a write to stdout
before fork
pid=14828,glob=7,var=89 //子进程的变量变了
pid=14827,glob=6,var=88 //父进程得变量值没变
zsj@zsj-virtual-machine:~/ccode$ ./a.out >temp.out
zsj@zsj-virtual-machine:~/ccode$ cat temp.out
a write to stdout
before fork
pid=14830,var=89
before fork
pid=14829,var=88
zsj@zsj-virtual-machine:~/ccode$

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

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

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

但是标准库是带缓冲的.

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

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

原文链接:https://www.f2er.com/bash/391961.html

猜你在找的Bash相关文章