Linux c学习之进程控制

来源:互联网 发布:孙禄堂 知乎 编辑:程序博客网 时间:2024/06/01 08:12

此篇不讲那么多理论知识,就来说说在这章学习当中遇到的问题,解决后的答案以及还需注意到的一些点:

       1、会话的概念;

              会话:一个或多个进程组的集合,开始于用户登录,终止于用户退出,此期间所有进程都属于这个会话期。

       2、内核为程序分配的内存空间,分为代码段,数据段,未初始化的数据段,堆栈段。在终端下size a.out  就可以查看可执行文件的段大小信息(a.out是可执行程序)。

       3、fork函数有两个返回值,因此,在程序中会进入两次switch语句中或者进行两次if条件判断。

       4、如果一个进程的父进程先于子进程结束,子进程又init进程收养。

#include <unistd.h>#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>int main(int argc, char *argv[]){pid_t pid;pid = fork();switch( pid ) {case 0:while(1) {printf("A background process,pid:%d\n,parentid: %d\n",getpid(),getppid());sleep(3);}case -1:perror("error!\n");exit(-1);default:printf("I am parent process, my pid = %d\n",getpid());exit(0);}return EXIT_SUCCESS;}
程序执行后,父进程先死,但最后得到ppid是1。这是因为init进程的进程号总是“1”.

如果内核启动时候没有找到init,它就会试着运行/bin/sh,如果还是失败,启动就会失败。

    5、书上提到vfork创建一个子进程时候,操作系统并不将父进程的地址空间完全复制到子进程。这里地址空间可以理解成数据段。

    6、守护进程的概念:是脱离于终端并且在后台运行的进程,守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断。

    7、创建守护进程时,用到一个setsid函数。setsid函数用于创建一个新的会话,并且担任该会话组的组长。

          这个函数的的作用是:<1>、让进程摆脱原会话的控制。

         <2>、让进程摆脱原进程组的控制。<3>、让进程摆脱原控制终端的控制。

         程序用setsid函数的原因:fork函数copy的父进程的数据域,包括父进程的会话期,进程组,控制终端等。

    8、进程退出时用到的exit()函数跟_exit()函数的区别:

          exit函数结束调用它的程序之前,要进行清除操作。

    9、

          #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 *path, char *const argv[], char *const envp[]);

          在用EXEC函数族时候,先来看一下函数原形。有几点需要说明一下:
           1、第一个参数是path的,这个参数说的是另一被执行程序的完整路径。而file可以直接是被执行的程序。
           2、第二个参数是const char* argv[],这个是传给被执行程序的参数。(程序可执行文件的名字)
           3、第三个参数是envp,这个是传给被执行程序的环境变量。而有的函数第三个参数是“....”,这个并不是省略的意思,而是默认把环境变量不做任何的修改,直接传给被执行的程序。
           4、再说一下  const char *p 与  char * const p 的区别。
                 const是定义一个常量的,因此,可以把const后面的给括起来,就成了const (char * p)与char * const (p),这下就好区分了,第一个是定义了一个字符型指针,因为是常量所以该指针只能指向一个参数,不能改变。而第二个是定义一个常量p,而指针不是常量指针,可以改变指向。

        贴一段代码:
#include <unistd.h>#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>extern char **environ;int main(int argc, char *argv[]){int i;printf("Arguement:\n");for( i = 0 ; i < argc ; i++ ) {printf("argv[%d] is %s\n",i,argv[i]);}printf("Environment:\n");for( i = 0 ; environ[i] != NULL ; i++ ) {printf("%s\n",environ[i]);}return EXIT_SUCCESS;}

注:如果在进程控制操作这里看到了(char *)0 或者(int *)0  这段代码,这个表示NULL的意思。



    10、下面先贴一段代码,再来分享:

#include <unistd.h>#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/wait.h>#include <sys/types.h>int main(int argc, char *argv[]){pid_t pid;char *msg;int k;int exit_code;printf("study how to exit code\n");pid = fork();switch(pid) {case 0:msg = "Child process is running!\n";k = 5;exit_code = 37;break;case -1:perror("process creation failed\n");exit(1);default:exit_code = 0 ;break;}if(pid != 0) {int stat_val;pid_t child_pid;child_pid = wait(&stat_val);printf("Child process has exited, pid = %d\n",child_pid);if(WIFEXITED(stat_val))printf("Child exited with code %d\n",WEXITSTATUS(stat_val));elseprintf("child exited abnormally\n");}else {while( k-- > 0 ) {puts(msg);sleep(1);}}exit(exit_code);}

<1>、先提一个问题,是我在看书时候提出来的:为什么stat_val没有赋值语句?
          经过查找思考后:wait函数的参数的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值,它指出进程是否是正常退出的,以及正常退出时的返回值。
<2>、WNOHANG:若pid指定的子进程没有结束,则waitpid()返回0,不予以等待。若结束,则返回该子进程 ID。
          WUNTRACED:若子进程进入暂停状态,则马上返回,但子进程结束状态不予以理会。

    11、在改变进程优先级时候,优先级越小,最先执行。root用户可以将优先级改成负数。 

0 0