Linux多任务编程——进程

进程编程常用函数

1--- fork

  pitd_t fork(void);
  创建一个新的子进程,其父进程为调用 fork() 函数的进程;
  返回值:成功:子进程返回 0,父进程返回 子进程 PID;失败 返回 -1;
  *1>新创建的子进程PID,与父进程PID不同;
  *2>子进程 从 fork() 返回值开始运行,返回值为 0;父进程 fork() 返回新创建的子线程 PID

 1 int main()
 2 {
 3     pid_t pid;
 4     if ((pid = fork()) == -1) {
 5         perror("fork");
 6         return 0;
 7     }    
 8     else if (pid == 0) {                //返回 0 代表子进程
 9         printf("The return value is %d In child process! My PID is %d, My PPID is %d\n", pid, getpid(), getppid());
10     }
11     return 0;
12 }

 

2--- exec函数族   

       exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

       与一般情况不同,exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样,颇有些神似"三十六计"中的"金蝉脱壳"。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回一个-1,从原程序的调用点接着往下执行。

  可以使用 fork 创建一个子进程,在子进程中进行 exec 函数的调用 去完成某些比较危险的操作。使用时一定要注意这一点。

  exec家族一共有六个函数,分别是: 

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

  (2)int execle(const char *path, const char *arg, ...... , char * const envp[]);

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

  (4)int execve(const char *filename, char *const argv[], char *const envp[]); 

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

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

  其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 int main()
 5 {
 6 /*调用execlp函数,相当于调用了 “ps -ef”命令*/
 7     if(execlp("ps", "ps", "-ef", NULL) < 0 8     {
 9         perror("ececlp error!");
10     }
11     return 0;
12 }

它们之间的区别:

  第一个区别是:
       前四个取路径名做为参数,后两个取文件名做为参数,如果文件名中不包含 “/” 则从PATH环境变量中搜寻可执行文件, 如果找到了一个可执行文件,但是该文件不是连接编辑程序产生的可执行代码文件,则当做shell脚本处理。

  第二个区别:
       前两个和最后一个函数中都包括“ l ”这个字母 ,而另三个都包括“ v ”, " l "代表 list即表 ,而" v "代表 vector即矢量,也是是前三个函数的参数都是以list的形式给出的,但最后要加一个空指针,如果用常数0来表示空指针,则必须将它强行转换成字符指针,否则有可能出错。,而后三个都是以矢量的形式给出,即数组。

  最后一个区别:
      与向新程序传递环境变量有关,如第二个和第四个以e结尾的函数,可以向函数传递一个指向环境字符串指针数组的指针。即自个定义各个环境变量,而其它四个则使用进程中的环境变量。

 

3--- exit( ) 和 _exit( )

  exit( )是标准库函数(Standard library)

  _exit( ) 时系统调用函数(system call)

  exit( ) 和 _exit( ) 都是用来终止进程的。当程序执行到 exit( )或 _exit( )时,进程会无条件地停止剩下的所有操作,清除各种数据结构,并终止本进程的运行。但是这连个函数还是有区别的:

 

4--- wait( ) 和 waitpid( )

  wait( )函数用于父进程(也就是调用它的进程)阻塞,直到一个子进程结束,或者接到一个指定信号为止,如果父进程没有子进程或者其他进程的子进程已经结束,则wait( )会立即返回 -1;

  waitpid( )的作用和wait( )一样,但并不一定等待第一个终止的子进程。waitpid( )有若干个选项,可以提供一个非阻塞版本的wait()功能。

函数原型:

  pid_t wait(int *status);  status 指向的整型对象用来保存进程结束时的状态。另外,子进程的结束状态可由linux中一些特定的宏来测定。

  返回值   成功:已回收子进程的进程号。    失败: -1

  pid_t waitpid(pid_t pid, int *status, int options);

  pid: pid > 0: 回收进程 ID 为 pid 的子进程

     pid = -1:回收任何一个子进程,此时和 wait()功能一样

       pid = 0:回收其组 ID 等于调用进程的 ID 的任一子进程

     pid < -1:回收其组 ID 等于 pid 的绝对值的任一子进程

  status:同wait()

  options:WNOHANG:若指定的子进程没有结束,则 waitpid()不阻塞而立即返回,此时返回值为 0

        WUNRTACED:为了实现某种操作,由pid 指定的任一子进程已被暂停,但其状态自暂停依赖还未报告过,则返回其状态

  返回值:>0:已结束运行的子进程的进程号

      0:使用 WNOHANG 且没有子进程退出

      -1:出错

 

5--- 守护进程 

  守护进程也就是通常所说的Daemon进程,他是 Linux 中的后台服务进程。 通常在系统启动时开始执行, 在系统关闭时终止。

  编写守护进程的步骤(5步):

   (1) 创建子进程,父进程退出。

    1 if0 < pid = fork()) {
    2      exit(0);                /*父进程退出*/
    3 }

 

   (2) 在子进程中创建新会话  (两个新的概念:进程组、会话期)

     进程组:一个或多个进程的集合。有进程组由进程组 ID 来唯一标识。除了进程号(PID)之外,进程组 ID 也是一个进程的必备属性。

     会话:会话是一个或多个进程组的集合。

     pit_t setsid(void);      成功:返回该进程组 ID    出错:返回 -1

     用于创建一个新的会话,并担任该会话组的组长。调用 setsid() 有下面三个作用。

     ① 让进程摆脱原会话的控制  ② 让进程摆脱原进程组的控制  ③ 让进程摆脱原控制终端的控制

   (3) 改变当前目录

     通常做法是让 “/” (根目录)作为守护进程的工作目录

   (4) 重设文件权限掩码

     umask(); 是设置文件权限掩码的函数,通常的使用方法是 umask(0);

   (5) 关闭文件描述符

    1 int num;
    2 num = getdtablesize();         //    获取当前进程文件描述表大小
    3 for (i = 0; i < num; i++)
    4 {
    5     close(i);
    6 }    

 

转载于:https://www.cnblogs.com/chen-farsight/p/6020795.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值