zoukankan      html  css  js  c++  java
  • 进程调度主要函数解析

    进程系统调用

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

    }

  • 相关阅读:
    BZOJ2821 作诗(Poetize) 【分块】
    BZOJ2724 蒲公英 【分块】
    Codeforces 17E Palisection 【Manacher】
    BZOJ2565 最长双回文串 【Manacher】
    Codeforces 25E Test 【Hash】
    CODEVS3013 单词背诵 【Hash】【MAP】
    HDU2825 Wireless Password 【AC自动机】【状压DP】
    HDU2896 病毒侵袭 【AC自动机】
    HDU3065 病毒侵袭持续中【AC自动机】
    HDU2222 Keywords Search 【AC自动机】
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3202851.html
Copyright © 2011-2022 走看看