进程的控制

 进程的属性,建立子进程,信号,进程的控制,进程的调度

进程的属性
    进程的组成元素
        * 进程的上下文
        * 进程的当前目录
        * 进程的权限
        * 进程访问的文件或目录
        * 进程分得的内存,等其他系统资源
    内核使用进程来控制对CPU和其他系统资源的访问。内核的调度器为每个进程分一个极短的时间段,来供进程执行其指令,该时间段称为时间片。即每个进程轮流执行一个时间片的时长。
    进程的标号
        能够唯一标识一个进程的非零的正整数称为PID(process ID),建立该进程的进程的PID是该进程的PPID(parent ID),即父进程号。所有的进程往上进行追溯,最终都会停在一个叫init的进程,这个进程是内核自举后第一个启动的进程。
        下表列出的函数用来得到对应的属性,在使用他们之前必须先,包含头文件unistd.h和sys/types.h两个头文件。
            函数                            属性            注释
            pid_t   getpid  (void); PID        
            pid_t   getppid (void); PPID           
            uid_t   getuid  (void); UID         登录用的ID
            uid_t   geteuid (void); 有效用户ID      文件的UID而不是执行者的UID,当程序设置了setUID或setGID时,UID和有效用户ID就变得不一样了
            gid_t   getgid  (void); GID         登录时的用户所在的组的ID
            gid_t getegid   (void); 有效组ID
        例如:
            #include <unistd.h>
            #include <sys/types.h>
            #include <stdio.h>

            int main(void)
            {
                printf("PID  : %4d\n", getpid());
                printf("PPID : %4d\n", getppid());
                printf("UID  : %4d\n", getuid());
                printf("eUID : %4d\n", geteuid());
                printf("GID  : %4d\n", getgid());
                printf("eGID : %4d\n", getegid());
       
                return 0;
            }
        运行结果为:
            PID  : 6200
            PPID : 6107
            UID  :  500
            eUID :  500
            GID  :  500
            eGID :  500
        当然,结果在不同的机器上会有不同,在这里,UID和eUID相同,是因为我执行的是一个属于UID为500的文件。
    用户信息和组的信息
        #include <unistd.h>
        char * getlogin (void); /*返回执行该程序用户登录的用户名,失败返回NULL*/

        #include <pwd.h>
        struct passwd * getpwnam (const char * name);/*得到用户信息,*/
        struct passwd {
              char   *pw_name;       /* user name */
              char   *pw_passwd;     /* user password */
              uid_t   pw_uid;        /* user ID */
              gid_t   pw_gid;        /* group ID */
              char   *pw_gecos;      /* real name */
              char   *pw_dir;        /* home directory */
              char   *pw_shell;      /* shell program */
                  };
        例如:
            #include <unistd.h>
            #include <stdio.h>
            #include <stdlib.h>
            #include <pwd.h>

            int main(void)
            {
                char * name;
                struct passwd * msg;
   
                if (NULL == (name = getlogin()))
                {
                    perror("getlogin error");
                    exit(EXIT_FAILURE);
                }
       
                if (NULL == (msg = getpwnam(name)))
                {
                    perror("getpwnam error");
                    exit(EXIT_FAILURE);
                }
   
                printf("user name      : %s\n", msg->pw_name);
                printf("user ID        : %d\n", msg->pw_uid);
                printf("group ID       : %d\n", msg->pw_gid);
                printf("real name      : %s\n", msg->pw_gecos);
                printf("home directory : %s\n", msg->pw_dir);
                printf("shell          : %s\n", msg->pw_shell);
   
                return 0;
            }
        输出为:
            user name      : gin
            user ID        : 500
            group ID       : 500
            real name      : hades gin
            home directory : /home/gin
            shell          : /bin/bash
    进程时间信息
        #include <sys/times.h>
        clock_t times (struct tms * buf); /*返回系统自自举后到目前的滴答数,buf保存了当前进程的时间信息。*/
        struct tms {
              clock_t tms_utime;  /* user time */
              clock_t tms_stime;  /* system time */
              clock_t tms_cutime; /* user time of children */
              clock_t tms_cstime; /* system time of children */
                   };
        例如:
        #include <stdlib.h>
        #include <stdio.h>
        #include <sys/times.h>
        #include <limits.h>
        #include <time.h>
        #include <unistd.h>

        int main(void)
        {
            long i = 0;
            clock_t start, end;
            struct tms tmmsg;
   
            start = times(&tmmsg);
            while (i++ < LONG_MAX);
            end = times(&tmmsg);
   
            printf("spend %f seconds\n",
                (float)(end - start) / sysconf(_SC_CLK_TCK));
            printf("user time : %f\n",
                (float)(tmmsg.tms_utime / sysconf(_SC_CLK_TCK)));
            printf("system time : %f\n",
                (float)(tmmsg.tms_stime / sysconf(_SC_CLK_TCK)));
   
            return 0;
        }
        输出结果为:
            spend 6.240000 seconds
            user time : 6.000000
            system time : 0.000000
       
    进程的资源信息
        struct rusage {
                struct timeval ru_utime; /* user time used */
                struct timeval ru_stime; /* system time used */
                long   ru_maxrss;        /* maximum resident set size */
                long   ru_ixrss;         /* integral shared memory size */
                long   ru_idrss;         /* integral unshared data size */
                long   ru_isrss;         /* integral unshared stack size */
                long   ru_minflt;        /* page reclaims */
                long   ru_majflt;        /* page faults */
                long   ru_nswap;         /* swaps */
                long   ru_inblock;       /* block input operations */
                long   ru_oublock;       /* block output operations */
                long   ru_msgsnd;        /* messages sent */
                long   ru_msgrcv;        /* messages received */
                long   ru_nsignals;      /* signals received */
                long   ru_nvcsw;         /* voluntary context switches */
                long   ru_nivcsw;        /* involuntary context switches */
                };
        利用该结构能够得到更多有用的信息,不过,在这里,真正能够个使用的只有ru_utime,ru_stime,ru_minflt,ru_majflt,ru_swap;其中ru_mainflt是指要访问的数据不在寄存器或者高速缓存上,需要到内存中读取,但没有磁盘上读取,ru_majflt数据在内存中也没有找到,必须要到磁盘中寻找。而ru_swap保存了因为major fault而必须从磁盘中读取的页数。
        #include <sys/time.h>
        #include <sys/resource.h>
        #include <unistd.h>
        int getrusage(int who, struct rusage * usage);
        其中who的取值有两个,要么是RUSAGE_SELF用来表示他自己,或者RUSAGE_CHILDREN表示其子进程的信息。成功返回0,否则返回-1;

    进程组和会话
        一个进程组是一个相关进程的集合,这些相关进程通常是在一个管道中的命令序列,在进程中,所有的进程都具有相同的进程组号,即PGID,使用进程组的目的是为了方便的进行作业控制,例如,当你在执行ls -l | grep str时按下Ctrl-C键会将这个进程组杀掉,而不是单单的某一个进程。
        会话由一个或多个进程组构成,会话领导进程是创建会话的进程,每一个会话都有唯一的标识号,称为会话ID,他只是会话领导进程的PID。
   
    创建进程
        使用system()函数
            他通过将system传递给/bin/sh -c来执行string所指定的命令。接着整个命令行(/bin/s -c string)又传递给系统调用execve,如果没有找到/bin/sh,则返回127.出现错误,则返回-1,否则返回string的代码,若string为NULL,则返回一个非零的值。
        fork系统调用
            使用fork进行创建子进程,则新的进程是父进程的完全拷贝。但是,子进程没有继承父进程的超时设置。父进程创建的文件锁,或者未决信号。
            如果调用成功,就向父进程返回子进程的PID,并向子进程返回0。如果失败返回-1。并将不会创建子进程。
                #include <sys/types.h>
                #include <unistd.h>
                pid_t fork(void);

        exec函数族
            #include <unistd.h>
            extern char **environ;
            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 *filename, char *const argv[],
                  char *const envp[]);
            exec用被执行的程序完全替换了调用进程的映像,他会启动一个新的程序来替换原有的进程,因此,进程的PID将不会被改变。
            其中,execve的调用类似main函数的 int main(int argc, char *argv[], char *envp[])形式。argv是以','间隔,并以NULL结束的字符数组。
            在这些函数中,path用来指明路径,当他是哟个目录的时候,则会像shell一样搜索$PATH,寻找执行文件。带 l的函数中,参数不需要以字符数组的形式出现,而是将其每一项作为参数传入函数。例如:
            execl("/bin/ls","/bin/ls","-l",NULL);
            使用带v的数组,则必须先构造一个字符数组,就向上面说的一样。在带参数envp的函数中,可以通过下面的函数进行环境变量的设置;
            #include <stdlib.h>
            int putenv(const char * string);
            char * grtenv(const cahr * name);
        使用popen函数
            #include <stdio.h>
            FILE * popen(const char * command, const char * type);
            int pclose(FILE * stream);
            popen调用管道,并创建通向标准输入或者从command指定的程序或脚本的标准输出来的管道,但不能两者同时使用。typw的取值为w,r,此时的读和写操作是相对于command的来说的。
       
控制进程
    等待进程
        当使用fork或exec创建了一个新的进程之后,为了收集进程退出的状态,并避免出现僵进程,父进程应该等待子进程终止,一个僵进程是在父进程有机会用wait或者waitpid收集他的退出状态之前就终止的子进程,父进程通过使用wait函数之一检索内核的进程表,取得退出状态来收集子进程的退出状态,之所以称其为僵进程是应为,他虽然死掉了,但仍然存在于进程表中,子进程退出后,分配给他的资源和内存被释放,但在内核的进程表中仍能看到该进程,内核在父进程收回其退出状态之前一直保留他。
        一个孤儿是一个父进程在调用wait或者waitpid之前就退出的子进程,这是,init就成为了该进程的父进程来收集其退出的状态。
         #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *status);
       pid_t waitpid(pid_t pid, int *status, int options);
        其中,pid的取值范围:
            -1     等待任何PGID等于PID的绝对值的子进程
            1       等待任何子进程
            0       等待任何OGID等于调用进程的子进程
            >0      等待PID为pid的子进程
        option规定了他的行为:
            WNOHANG     导致waitpid在没有子进程退出时,立即返回
            WUNTRACED   应该因为存在没有报告状态的进程而返回
            两个值相  或    取得两种行为
    进程的终止
        `return
        `exit
        `_exit
        `abotr
        `收到信号终止
    使用kill杀死进程
         #include <sys/types.h>
       #include <signal.h>
       int kill(pid_t pid, int sig);
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值