Linux环境C/C++编程笔记之外部进程启动相关问题记录

可以使用的几种启动外部进程的方式

  • std::system(cmd)函数
  • popen(cmd)函数
  • fork/vfork + exec系列函数

各函数的使用方法

std::system

  1. 包含头文件 或者
  2. 函数形式:
int system(const char *command);
  1. 函数说明
  • 参数command: 表示shell中的命令行内容, 比如 ls -la
  • 返回值: 返回子进程所调用的外部程序退出时的return
  1. 使用场合: 当需要执行某个外部命令并且只关心该命令是否成功的话建议使用

popen

  1. 包含头文件: 或者
  2. 函数形式:
FILE * popen(const char *command, const char *mode);
  1. 参数说明:
  • command:和system的参数含义类似,表示命令行参数内容
  • mode: 进程管道的打开模式, 主要有两类"r""w",分别表示以只读或者只写的方式打开子进程的管道,读取对应子进程的stdout,写入对应子进程的stdin。部分平台支持 "r+"模式打开子进程管道, 表示可以读写
  1. 返回值: 子进程管道的文件句柄
  2. 需要配合使用 pclose对管道进行关闭,具体形式为:
int pclose(FILE *stream);
  1. 注意: pclose不会终止子进程的运行, 需要使用进程间通讯的方式在pclose之前通知子进程退出, 再通过pclose对管道资源进行回收。使用不当容易导致父进程无法正常退出甚至子进程变成僵尸进程或者孤儿进程
  2. 适用场合: 当需要指定某个(最好是短时间完成的)外部命令并获得该命令的标准输出结果或者需要对外部命令传达标准出入参数的时候适用, 服务类子进程不适合, 除非实现父子进程之间的通信保证父子进程之间的生命周期关系

fork()/vfork() + exec

函数介绍:

  1. fork()vfork()

    • 表示拷贝父进程的数据开启一个新进程,
    • 都会分别在父子进程中返回一次, 在父进程中, 返回的是子进程的PID, 在子进程中, 返回0,返回小于0的值表示fork失败
    • vfork() 相比fork() 会有个确保子进程先运行的机制, 当子进程退出或者运行了exec函数后,父进程才恢复运行状态
  2. exec函数

  • 不是指某一个函数, 而是某一类函数, 统称 exec函数, 具体如下:
int execl(const char *path, const char *arg0, ... /*, (char *)0 */);

int execle(const char *path, const char *arg0, ... /*, (char *)0, char *const envp[] */);

int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);

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

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

int execvP(const char *file, const char *search_path, char *const argv[]);
  • 其中的file指的是命令对应的文件名, path指的是命令的路径

  • 使用文件名的exec函数会在内部主动根据环境变量PATH转化为命令路径, 再转化为调用 path参数的exec函数

  • exec后面的l表示该函数的argv参数以可变参数列表的形式传入, 以0/NULL/nullptr结尾

  • exec后面的p表示需要传入环境变量内容 envp

  • exec后面的v表示传入的argv参数是以向量的形式传入,向量的最后一个值为0/NULL/nullptr表示结束

  1. 适用场合: 子进程和父进程一样需要长时间驻留后台运行并且可以由父进程控制子进程的生命周期时适用这种形式的管理方式

  2. 注意事项: exec函数的第一个参数表示的是命令, 该命令不会出现在子进程的argv中, 因此子进程的argv是从exec的第二个参数开始的一次对应argv[0], argv[1],…

  3. 通过fork/vfork + exec函数形式创建的子进程, 可以通过kill函数发送进程退出信号来结束子进程, 并通过 wait函数来等待子进程结束并清理资源

  4. kill函数位于头文件,形式如下:

// pid表示需要发送信号的进程PID
// signal表示要发送的信号, 常用的结束进程的信号有:
// SIGINT: 2, 中断信号
// SIGNTERN: 15, 终止信号
// SIGKILL: 9, 杀死信号, 有资源泄漏的风险, 尽量少用
int kill(pid_t pid, int signal);
  1. wait函数位于头文件, 形式也不止一种, 比如: `
pid_t wait(int *stat_loc);

pid_t wait3(int *stat_loc, int options, struct rusage *rusage);

pid_t wait4(pid_t pid, int *stat_loc, int options, struct rusage *rusage);

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

具体使用可以通过 man wait4的方式查看详细文档

你可能感兴趣的:(Linux,多进程,linux)