进程调度主要函数解析

 

进程系统调用

 

函数fork();

其原型pid_t fork(void);其在头文件

#include<sys/types.h>,#include<unistd.h>

这个函数的返回值:如果是出错返回-1

如果是成功的话返回两次,对于父进程返回子进程的进程号,对于子进程返回0

 

对于fork()这个函数,我这里要简要的分析一下:注意下面的言语是我自己理

解的仅供参考:

 

fork()解析:

分析一:

首先如果在一个程序中调用fork(),那么当前这进程就会作为一个父亲进程创建

一个子进程,这个创建的过程,实际上是把当前这个父进程的所有资源复制一份

给其子进程,但是,虽然是copy了一份“基因”,其功能也可能不一样,要根据

你自己的代码是怎样实现的

 

分析二:

在功能部分,我们把父进程和子进程看做是在同一起跑线的参赛者,开始谁线领

先,要根据裁判员(也就是系统,要根据当时的情况,所以程序员是不清楚谁先

运行),但是这个差别可以说是趋近与零,也就是父进程和子进程同时“起跑”

,如果父进程跑的漫的话(sleep(10),跑到一个位置休息10秒),那么子进程就

会超越父进程,因而其在此时其先于父进程执行其功能,如果执行了一段时间,

子进程也休息了(sleep(10)),但是此时父进程已经休息完了(即两者又在同一

起跑线),那么父进程又超越子进程,因而会先于子进程执行其功能部分,一直到

两者都完全跑到终点(全都执行完成,或者因为某种原因直接到了终点),此时

裁判员完成后续的操作(系统完成后续的操作)。

 

如下例子:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

 

int       glob = 6;               /* external variable in initialized 

data */

char    buf[ ] = "a write to stdout\n";

//char    buf[ ] = "a write to stdout";

int  main(void)

{

        int       var;            /* automatic variable on the stack */

        pid_t   pid;

        var = 88;

        if ((write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-

1))

                { printf("write error"); exit(1); }

        printf("before fork\n");        /* we don't flush stdout */

        //printf("before fork");        /* we don't flush stdout */

        if ( (pid = fork()) < 0)

                { printf("fork error"); exit(2); }

        else if (pid == 0) {            /* child */

                glob++;                                 /* modify 

variables */

                var++;

        } else

                sleep(2);                               /* parent */

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

(),getppid(), glob, var);

        exit(0);

}

 

 

 

对于exec函数族:

 

这个函数族的重要功能在于:让自己执行新的程序;具体来讲就是,当进程认为

自己不能再为系统做任何贡献时,就可以调用exec函数,转而区执行其他的程序

 

 

其中有六个成员:其原型分别为:

       int execl(const char *path, const char *arg, ...);

       int execlp(const char *file, const char *arg, ...);

       int execle(const char *path, const char *arg,

                  ..., char * const envp[]);

       int execv(const char *path, char *const argv[]);

       int execvp(const char *file, char *const argv[]);

int execve(const char *path,char *const argv[],char *const 

envp[]);

 

下面我用源码一一来实现对这几个函数的操作;

 

函数一:int execl(const char *path, const char *arg, ...);代码中有注释

,具体使用可以查man手册,这才是王道

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 int main(int argc,char *argv[]){

  4 //对于execl(path,mend,...),对于第一个参数是你需要执行的二进制文件

>    全路径名,第二个参数是你要执行的命令,或者说可执行文件,后面的参

数是>    可选的参数(就是你的可执行文件可能带有的参数,任意选取),但是

一定要NULL结束

  5         execl("/bin/ls","ls","-l","-a",NULL);

  6         printf("sorry\n");

  7 }

         

函数二:  int execlp(const char *file, const char *arg, ...);你只需给出

命令,或者可执行的文件,系统可以通过环境变量来查找

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 int main(int argc,char *argv[]){

  4 //execlp()execl()区别在于第一个参数是要执行的文件名,而非全路径,

也可以,可执行文件的路径

  5         execlp("ls","ls","-l","-a",NULL);

  6         printf("sorry\n");

  7 

  9 }

 

函数三:int execle(const char *path, const char *arg,

                  ..., char * const envp[]);可以传入环境变量

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 int main(int argc,char *argv[]){

  4         char *env_t[]={"PATH=/bin/ls",NULL};

  5 ///execle(),第一个参数是要执行文件的路径,第二个参数是要执行的命令

>    后面的该命令,或者该可执行文件的可轩参数,知道NULL,最后一个参数

是该>    可执行文件要找的环境变量

  6         execle("/bin/ls","ls",NULL,env_t);

  7         printf("to here\n");

  8 }

 

函数四:int execv(const char *path, char *const argv[]);表示将所有参数

构造成指针数组传递

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 int main(int argc,char *argv[]){

  4         char *pass[3];

  5         pass[0]="ls";

  6         pass[1]="-l";

  7         pass[2]=NULL;  //NULL这里不能用双引号

  8 //execv(const char *path,char *const argv[]);这里第一个参数表示你要

    行的的可执行文件的全路径放进去

  9         execv("bin/ls",pass);

 10         printf("to here\n");

 11 }

~                                                                       

 函数五: int execvp(const char *file, char *const argv[]);

~ 1 #include<stdio.h>

  2 #include<unistd.h>

  3 int main(int argc,char *argv[]){

  4         char *pass[3];

  5         pass[0]="ls";

  6         pass[1]="-l";

  7         pass[2]=NULL;  //NULL这里不能用双引号

  8 //这里execvp(const char *file,char *const argv[]);第一个参数,可以

>    要执行命令的全路径,也可以是命令,他会到环境变量里面去找到相关的

命令

  9         execvp("ls",pass);

 10         printf("to here\n");

 11 }

 

函数六:int execve(const char *path,char *const argv[],char *const 

envp[]);

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 int main(int argc,char *argv[]){

  4         char *pass[3];

  5         pass[0]="ls";

  6         pass[1]="-l";

  7         pass[2]=NULL;

  8         char *env_t[]={"PATH=/bin/ls",NULL};

  9 ////execve();第一个参数是全路径,第二个参数是命令,第三个参数是该命

    的的环境变量路径

 10         execve("/bin/ls",pass,env_t);

 11         printf("to here\n");

 12 

 13 

 14 }

 

 

 

对于wait()函数:

其原型:pid_t wait(int *status);

 

函数说明:wait()会暂时停止目前进程的执行直到有信号来到或子进程结束

如果在调用wait()时子进程已经结束wait()会立即返回子进程结束状态值

子进程的结束状态值会由参数status 返回而子进程的进程识别码也会一快返回

如果不在意结束状态值则参数 status 可以设成NULL. 子进程的结束状态值

请参考waitpid().

 

下面是我的一个小shell(非原创):

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include 

<fcntl.h>

#include <errno.h>

#include <sys/types.h>

#include 

<sys/wait.h>

#include <string.h>

int parseargs(char * cmdline);

char 

*cmdargv[20] = {0};

int main(void)

{

pid_t pid;

char buf[100];

 

int retval = 1;

printf("WoLaoDa# ");

fflush(stdout);

 

while (1) {

fgets(buf, 100, stdin);

buf

[strlen(buf) - 1] = '\0';

if ((pid = fork()) < 0) {

 

perror("fork");

exit(-1);

 

} else if (pid == 0) {

sleep(5);

 

parseargs(buf);

execvp(cmdargv[0], 

cmdargv);

exit(0);

}

 

wait(&retval);

//printf("retval = %d\n", retval);

 

printf("WoLaoDa# ");

fflush(stdout);

}

}

 

int 

parseargs(char * cmdline)

{

char *head, *tail, *tmp;

int i;

 

head = tail = cmdline;

for( ; *tail == ' '; tail++)

;

 

head = tail;

for (i = 0; *tail != '\0'; i++) {

 

cmdargv[i] = head;

for( ; (*tail != ' ') && (*tail != 

'\0'); tail++)

;

if (*tail == '\0')

 

continue;

*tail++ = '\0';

 

for( ; *tail == ' '; tail++)

;

head = 

tail;

}

cmdargv[i] = '\0';

return i;

}

 

posted @ 2013-07-20 18:49  坚固66  阅读(316)  评论(0编辑  收藏  举报