Linux进程概述:
什么叫进程呢?进程是一个程序的一次执行过程。它和程序是有本质区别的,程序是静态的,是及其代码指令和数据的集合,这些指令和数据存储在磁盘上的一个可执行映像中,没有任何执行的概念;而进程是动态的,它是执行的过程,包括了动态创建、调度和消亡的整个过程。
进程是程序执行和资源管理的最小单位。因此,对系统而言,当用户在系统中敲入命令执行一个程序的时候,它将启动一个进程。
Linux是多任务多用户的操作系统,也就是是可以多个程序同时装入内存并运行,操作系统为每个程序建立一个运行环境即创建进程。从逻辑上讲,每个进程拥有自己的虚拟CPU。当然,实际上真正的CPU在各进程之间快速的来回切换。
进程结构:
在Linux系统中,每一个进程都拥有独立的虚拟地址空间。进程间是分离的任务,拥有各自的权力和责任。Linux中的进程包括了3个段,分别为“数据段”,“代码段”,和“堆栈段”。
数据段: 存放的数据为全局变量、常数及动态数据分配的数据空间(如 malloc函数获取的虚拟空间)等。
代码段:顾名思义就是存放程序代码数据。
堆栈段:存放的是子程序返回地址、子程序的参数及程序的局部变量。
进程属性:
进程最主要的属性就是进程号(PID,Process ID),和它的父进程号,(PPID,parent process ID)。其中PID唯一的标识一个进程。PID和PPID都是一些非零的正整数,在 Linux中获得当前进程的PID和PPID的系统调用函数为getpid(),和getppid(),通常程序获得当前进程的PID和PPID可以将其写入日志文件以做备份。
进程是Linux系统的基本调度单位,那么从系统的角度看如何描述并表示它的变化呢?在这里,是通过进程控制块来描述的。进程控制块包含了进程的描述信息、控制信息以及资源信息,它是进程的一个静态描述。在Linux中,进程控制块中的每一项都是一个task_struct结构。
进程的基本状态有三种:
(1)、运行态:进程占有CPU,并在CPU上运行
(2)、就绪态:进程已经具备运行条件,仅仅缺少占有CPU的机会。(万事具备,只欠东风)
(3)、阻塞态:进程因等待某种事件的发生而暂时不能运行。即使CPU有空,它也不会理你。
调度只会选择就绪态的其中一个最合适的进程来占有CPU,而不会从阻塞态、运行态中取选择。
它们之间的转换关系如图所示:
进程创建:
1、fork()
在进程中使用fork函数,则会创建一个新进程,新进程则成为子进程,原进程则称为父进程。恰巧,这个fork函数执行一次却返回二个值。其中父进程中返回值是子进程的进程号(大于0的一个整数),子进程则返回0,因此,可以通过返回值来判断哪个是子进程哪个是父进程。
使用fork函数得到的子进程是父进程的一个复制品,它从父进程那里继承了整个进程的地址空间。包括进程上下文,进程堆栈、内存信息、打开文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。因此可以知道,使用fork函数的代价是非常大的。它复制了父进程中的代码段、数据段和堆栈段里的大部分内容,使得fork函数的执行速度有限。
fork函数语法:
所需头文件: #include<sys/types.h> //提供类型pid_t 的定义
#include<unistd.h>
函数原型:pid_t fork(void)
函数返回值:在子进程中返回0;在父进程中返回子进程的进程号PID;如果失败则返回 -1
使用注意点:fork函数使用一次就创建一个进程。
exec 函数族语法:
所需头文件:#include<unistd.h>
函数原型:int execl(const char *path,const char *arg,...)
int execv(const char *path,char *const argv[ ])
int execle(const char *path,const char *arg,...,char *const envp[ ])
int execve(const char *path,char *const argv[ ],char *const envp[ ])
int execlp(const char *file,const char *arg,...)
int execvp(const char *file,char *const argv[ ])
函数返回值: -1,出错;成功执行时,没有返回值。
l:参数传递为逐个列举方式,如:execl、execle、execlp
v:参数传递为构造指针数组方式,如:execv、execve、execvp
e:可传递新进程环境变量,如:execle、execve
p:可执行文件查找方式为文件名,如:execlp、execvp
下面为fork,getpid,getppid,execlp,execl的简单综合利用程序:
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t pid;
pid=fork();
if(pid<0)
{
perror("fork error");
exit(1);
}
if(pid==0)
{
printf("This is a child process,PID is %d.\n",getpid());
if(execlp("ls","ls","-l",NULL)<0)
{
perror("execlp error");
exit(1);
}
}
printf("---------------------------------------------------\n");
if(pid>0)
{
printf("This is a parent process,PPID is %d.\n",getppid());
if(execl("ls","ls","-l",NULL)<0)
{
perror("execl error");
printf("*****************************************************\n");
}
printf("Now it will run execl()\n");
printf("*****************************************************\n");
if(execl("/bin/ls","ls","-l",NULL)<0)
{
perror("execl error");
}
}
return 0;
}
执行结果为:
使用exec族函数应该注意的地方,一定要加上错误判断语句。因为exec很容易执行失败,其中最常见的错误有:
(1)、找不到文件或路径,此时errno被设置为ENOENT;
(2)、数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT;
(3)、没有对应可执行文件的运行权限,此时errno被设置为EACCES。
system函数语法:
所需头文件:#include<stdlib.h>
函数原型:int system(const char *string)
函数返回值:执行成功则返回执行shell命令后的返回值,调用/bin/sh失败时则返回127,其他失败原因则返回-1
/*system.c*/
#include<stdio.h>
#include<stdlib.h>
int main( )
{
int result;
result=system("ls -l");
return 0;
}
wait和waitpid函数:
wait函数是用于使父进程阻塞,直到子进程终止或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经终止,则wait就会立即返回。
waitpid函数的作用和wait一样,但是它并不一定要等待第一个终止的子进程,它还有若干项,如可提供一个非阻塞版本的wait功能。
wait()函数语法:
所需头文件:#include<sys/types.h>
#include<sys/wait.h>
函数原型:pid_t wait(int *status)
函数传入值:status若为空,则代表任意状态结束的子进程;
status若不为空,则代表指定状态结束的子进程;
函数返回值:成功:已结束运行的子进程的进程号;失败:-1
waitpid()函数语法:
所需头文件:#include<sys/types.h>
#include<sys/wait.h>
函数原型:pid_t waitpid(pid_t pid,int *status,int options)
函数传入值:
pid,
如果pid>0,只等待进程ID等于PID的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有退出,waitpid就会一直等下去。
如果pid=1,等待任何一个子进程退出,此时和wait作用一样。
如果pid=0,等待其组ID等于调用进程的组ID的任一子进程。
如果pid<1,等待其组ID等于pid的绝对值的任一子进程。
status,同wait的status
options,
WNOHANG:若由pid指定的子进程不立即可用,则waitpid不阻塞,此时返回值为0.
WUNTRACED:若实现某支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停一来还未报告过,则返回其状态。
0:同wait,阻塞父进程,等待子进程退出。
函数返回值:正常:子进程的进程号;
options使用WNOHANG且没有子进程退出则返回0;
调用出错:-1
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t pid1,pid_return;
pid1=fork();
if(pid1<0)
{
perror("fork error");
}
else if(pid1==0)
{
printf("sleep 5s in child process.\n");
sleep(5);
exit(0);
}
else
{
do
{
pid_return=waitpid(pid1,NULL,WNOHANG);
if(pid_return==0)
{
printf("The child process has not exited.\n");
sleep(1);
}
}while(pid_return==0);
if(pid_return==pid1)
{
printf("The child process has exited.\n");
}
}
return 0;
}
运行结果:
这节就讲到这里。^_^,^_^