• 进程调度主要函数解析


    进程系统调用

    函数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 ";

    //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 ");        /* 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 ", 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 ");

      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 ");

      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 ");

      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 ");

     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 ");

     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 ");

     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] = '';

    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 ", 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 != ''; i++) {

    cmdargv[i] = head;

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

    ''); tail++)

    ;

    if (*tail == '')

    continue;

    *tail++ = '';

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

    ;

    head = 

    tail;

    }

    cmdargv[i] = '';

    return i;

    }

  • 相关阅读:
    Centos 环境变量
    Centos 多线程下载工具-axel
    【Sprint3冲刺之前】项目可行性研究报告
    【Sprint3冲刺之前】TDzhushou软件项目测试计划书
    【Sprint3冲刺之前】日历表的事件处理和管理(刘铸辉)
    【Sprint3冲刺之前】项目完成时间表
    【Sprint3冲刺之前】敏捷团队绩效考核(刘铸辉)
    【每日Scrum】第八天(4.29) TD学生助手Sprint2
    【每日Scrum】第七天(4.28)Sprint2总结性会议
    需求分析
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3202851.html
Copyright © 2020-2023  润新知