系统调用一个程序以进程的状态在虚拟内存的空间要访问硬件资源的时候,内核提供系统调用的接口。
每个进程有唯一的ID标识,其实在系统中也有一类进程,被称为调度进程,此进程也被称为系统进程,其ID为0,但是INIT进程是一种普通进程它的ID为1,一般为系统启动的时候就已经运行了,以一种后台守护进程方式存在的。当一个进程在内存中,可以通过fork()函数来创建一个子进程,一个子进程完全复制了父进程的数据空间,堆栈的副本。这里奥注意的是子进程返回父进程的PID,而父进程返回子进程的PID,一般父进程和子进程谁先执行的顺序是不确定的,这要取决于内核的运行状态,
fork处理文件描述符一般有两种情况:
【1】父进程等待子进程完成,在这种情况下,父进程无需对文件描述符进行处理,当子进程处理完,对于它的读写操作时文件偏移量已经做了相应的更新,
【2】父进程和子进程执行各自不同的程序段,这里会引入EXEC函数,他们拥有各自的程序段,和文件描述符和偏移量,
(对于fork函数是在进程开始之前就完全复制了父进程的整个地址空间,这样执行速度比较慢,但在UNIX中通过vfork函数同样也创建新的进程,但不产生父进程的副本,它允许父子进程访问相同的物理空间,从而伪装了对进程空间的真实拷贝,只有在子进程要改变数据的时候才会拷贝,因此被称为写操作时拷贝)
下面是fork()函数的一般形式:
#include
#include
#include
#include
#include
int a = 7; int main () { int b = 33; pid_t pid; pid = fork(); if (pid == -1){ perror("fork"); exit (-1); }else if (pid == 0){ printf("a = %d,b = %d,mypid = %d,myppid = %d\n",a,b,getpid(),getppid()); a++; b++; printf("a = %d,b = %d,mypid = %d,myppid = %d\n",a,b,getpid(),getppid()); exit (-1); }else{ printf("a = %d,b = %d,mypid = %d,myppid = %d\n",a,b,getpid(),getppid()); exit (-1); } return 0; }
exec的示例程序:
#include
#include
#include
#include
#include
int a = 7; int main () { int b = 33; pid_t pid; pid = fork(); if (pid == -1){ perror("fork"); exit (-1); }else if (pid == 0){ printf("a = %d,b = %d,mypid = %d,myppid = %d\n",a,b,getpid(),getppid()); // if (execl("/bin/ps","ps","-au",NULL) < 0 ) if(execlp("ps","ps","-au",NULL) < 0) // if(execle("ps","ps","-au",NULL) < 0) perror("execl"); printf("this is printf\n"); exit (0); printf("a = %d,b = %d,mypid = %d,myppid = %d\n",a,b,getpid(),getppid()); exit (-1); }else{ sleep(2); printf("a = %d,b = %d,mypid = %d,myppid = %d\n",a,b,getpid(),getppid()); exit (-1); } } /* * 这里的execl要使用绝对路径,而对于execlp可以直接使用文件名, * L表示后面参数以列表的形式的列出来 * 对于后面的e环境变量可以使用数据的形式表示 * * * */