东莞万江网站建设,东莞市网络seo推广平台,详细描述建设网站,网站期刊怎么做进程创建-fork和system函数使用 文章目录进程创建-fork和system函数使用1、system()函数2、fork()函数3、继承关系#xff1a;4、一些FAQ一般情况下我们可以打开终端#xff0c;直接执行./demo等命令执行一个程序#xff0c;此时程序以进程的形式运行#xff0c;大概率程序…进程创建-fork和system函数使用文章目录进程创建-fork和system函数使用1、system()函数2、fork()函数3、继承关系4、一些FAQ一般情况下我们可以打开终端直接执行./demo等命令执行一个程序此时程序以进程的形式运行大概率程序的父进程是执行此命令对应的shell进程。实际应用中大概是在程序中完成进程的创建简单常用的可以用system命令调用比如system(“./demo ”) 或者使用fork创建一个子进程本文介绍这两种方法的区别和使用注意事项。1、system()函数主程序在代码中执行system函数相当于利用shell新开一个独立的进程此时shell的父进程为原始程序system中执行的命令是新开一个进程此时该命令的父进程为shell相对主程序来说system中执行的进程变成了孙子进程如下主进程(PID1000)└── sh(PID1001) # system启动的shell└── sleep(PID1002) # shell执行的命令另外需要注意的是sytem中使用和不使用存在区别不使用会阻塞主程序直到system调用的程序运行结束才会执行主程序的代码。如果system调用的程序是一直运行的需要加符号后台运行此时system会立即返回不会阻塞主进程但由于system返回了、会导致后台进程成为孤儿进程。#include stdlib.h #include stdio.h int main() { printf(父进程开始\n); // 情况1: 阻塞执行 printf( 阻塞执行 \n); int ret1 system(sleep 3 echo 阻塞命令完成); printf(system返回: %d\n, ret1); // 情况2: 非阻塞执行使用 printf(\n 非阻塞执行 \n); int ret2 system(sleep 3 echo 非阻塞命令完成 ); printf(system立即返回: %d\n, ret2); printf(父进程继续执行...\n); sleep(5); // 等待后台进程 return 0; }2、fork()函数fork函数是在主程序运行过程中直接创建子进程需要关注的是fork函数是一次调用两次返回fork()的返回值有三种情况它用来区分父进程和子进程这种设计使得父进程和子进程可以在同一个代码中执行不同的逻辑路径具体先执行父进程还是子进程受到操作系统调度影响是非阻塞的#include unistd.h #include stdio.h #include sys/types.h int main() { printf(准备调用fork()...\n); pid_t pid fork(); if (pid 0) { fprintf(stderr, fork失败\n); return 1; } else if (pid 0) { // 子进程 printf(这是子进程:\n); printf( fork()返回值: %d\n, pid); // 应该是0 printf( 自己的PID: %d\n, getpid()); printf( 父进程PID: %d\n, getppid()); // 子进程可以执行不同的任务 sleep(1); // 模拟工作 printf(子进程结束\n); return 10; // 子进程退出码 } else { // 父进程 printf(这是父进程:\n); printf( fork()返回值: %d (这是子进程的PID)\n, pid); printf( 自己的PID: %d\n, getpid()); printf(父进程结束\n); } return 0; }程序的返回为准备调用fork()... 这是父进程: fork()返回值: 3683 (这是子进程的PID) 自己的PID: 3682 父进程结束 这是子进程: fork()返回值: 0 自己的PID: 3683 父进程PID: 3682 图解说明 调用 fork() ↓ ┌───────────────┐ │ 创建子进程副本 │ └───────────────┘ ↓ 父进程继续执行 子进程开始执行 ↓ ↓ 返回子进程的PID 返回 0 ↓ ↓ 执行 pid 0 分支 执行 pid 0 分支 ↓ ↓ 各自独立运行互不影响fork函数在创建进程之后可以配合exec()的各种函数即在返回的pid0的分支调用exec函数执行自己新开的程序命令。#include unistd.h // 函数原型 int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[], char *const envp[]); l (list)参数以列表形式传递 v (vector)参数以数组形式传递 p (PATH)在PATH环境变量中查找程序 e (environment)可以指定新的环境变量具体的函数用法可以网上搜举两个常用简单例子//// execl pid_t pid fork(); if (pid 0) { // 子进程 execl(./codebin, codebin, code.cfg, NULL); // 第一个参数需要时为程序的执行路径 // 如果exec失败才会执行到这里 perror(execl失败); exit(1); } //// execv pid_t pid fork(); if (pid 0) { // 子进程 char *args[] {./codebin, code.cfg, NULL}; execv(./codebin, args); perror(execv失败); exit(1);3、继承关系system和fork在创建进程的时候会继承父进程的很多属性例如1.环境变量当前进程的所有环境变量都会被继承2.当前工作目录子进程会继承父进程的工作目录3.进程组和会话通常在同一会话和进程组中4.信号处理某些信号处理方式会继承5.文件描述符打开的文件描述符会继承(标准输入/输出/错误除外会被重定向)等demo例子#include unistd.h #include sys/types.h #include sys/wait.h #include stdio.h #include stdlib.h #include fcntl.h int main() { // 环境变量 - 会被继承 setenv(MY_VAR, parent_value, 1); // 文件描述符 - 会被继承 int fd open(test.txt, O_CREAT | O_WRONLY, 0644); write(fd, 来自父进程\n, 12); // 进程组、会话、工作目录等 - 会被继承 printf(父进程PID: %d, 工作目录: %s\n, getpid(), getcwd(NULL, 0)); pid_t pid fork(); if (pid 0) { // 子进程 printf(子进程PID: %d\n, getpid()); printf(环境变量MY_VAR: %s\n, getenv(MY_VAR)); // 可以访问父进程打开的文件 write(fd, 来自子进程\n, 12); close(fd); // 改变环境变量只影响子进程 setenv(MY_VAR, child_value, 1); // 执行新程序 char *argv[] {./other_program, NULL}; char *envp[] {MY_VARexec_value, PATH/bin, NULL}; // 不同的exec变体提供不同的控制 // execv(./other_program, argv); // 继承所有环境变量 // execve(./other_program, argv, envp); // 指定新环境变量 // execl(/bin/ls, ls, -l, NULL); // 列表参数 exit(0); } else { // 父进程的环境变量不变 printf(父进程中的MY_VAR: %s\n, getenv(MY_VAR)); close(fd); wait(NULL); } return 0; }4、一些FAQ继承有时候可能存在问题比如子进程如果一直占用某些文件描述符即使父继承显示关闭了需要卸载驱动或者其它不允许设备被占用的操作都容易出现问题这种情况下不需要继承的fd设置FD_CLOEXEC,会在调用exec函数的时候自动关闭问题1子进程可以继承父进程打开的文件描述符吗答可以子进程获得父进程文件描述符表的副本相同的fd编号指向相同的文件表项问题2会因为父进程占用了而打不开吗答不会每个进程有自己的文件描述符表多个进程可以同时打开同一个文件限制通常来自系统级如打开文件总数限制问题3子进程继承后父进程关闭子进程还在占用吗答是的每个fd有独立的引用计数父进程关闭只减少自己那份的引用计数子进程的引用仍然存在问题4此时其它进程能占用吗答能其他进程可以正常打开同一个文件文件是否真正被占用取决于文件锁