当前位置: 首页 > wzjs >正文

网站建设开票分类编码电脑与手机上同步wordpress

网站建设开票分类编码,电脑与手机上同步wordpress,查建筑公司资质的网站,网站php怎么做代码逻辑 核心思想 解析命令行,拆解命令及其选项创建子进程,在子进程中执行命令如果是前台执行命令,则父进程就阻塞等待子进程中命令执行结束后回收子进程的资源如果是后台执行命令,则父进程不进行阻塞等待,可继续向下…

代码逻辑

核心思想

  • 解析命令行,拆解命令及其选项
  • 创建子进程,在子进程中执行命令
  • 如果是前台执行命令,则父进程就阻塞等待子进程中命令执行结束后回收子进程的资源
  • 如果是后台执行命令,则父进程不进行阻塞等待,可继续向下运行,但为了防止僵尸进程的出现,需要设置一个信号函数,当后台子进程的命令执行结束后,会给父进程发送一个SIGCHLD信号,父进程的信号函数收到该信号后知道子进程执行结束了,于是执行waitpid系统函数回收子进程

小知识

僵尸进程

  • 每个进程都有一个父进程,当该进程执行结束后,其资源需要被父进程回收,否则会占用系统资源。
  • 父进程回收子进程的办法就是通过调用waitpid函数阻塞等待子进程的执行结束。
  • 僵尸进程就是指当一个进程结束之后,父进程由于一些原因迟迟不回收其子进程的资源,从而导致该进程一直占用着系统资源,这时该进程就成为僵尸进程

比如,当一个父进程由于业务原因需要一直运行,那么由他所创建的子进程结束之后,如果不进行回收就会成为一个僵尸进程,而该父进程由于业务原因也不可能阻塞等待子进程执行结束之后回收子进程,此时就需要设置信号函数来回收进程

孤儿进程

与僵尸进程对应的还有一个概念叫孤儿进程

前面我们说,每个进程都一个父进程,负责将其所创建的子进程执行结束之后回收子进程的资源,但前提是,父进程需要活到子进程执行结束的时候,因此如果该子进程执行结束之前,父进程先挂掉了,这种情况下的子进程就叫孤儿进程

但孤儿进程的危害其实并不大,尽管父进程挂掉了,但是还有祖宗收场,因此,系统会将孤儿进程挂到进程号为0,也就是init进程下,由他负责回收孤儿进程的资源

信号

  • 信号是进程间通信的一种机制,通常用来通知进程发生了某种事件,如中断、错误或特定条件的满足。
  • 信号可以被发送到进程以提醒其执行特定操作,例如终止、暂停或处理错误。
  • 常见的信号包括 SIGINT(中断信号)、SIGTERM(终止信号)等。通过信号,程序可以对系统事件进行响应,提高灵活性和控制能力。

本文中的shell代码中涉及到了SIGCHLD信号的使用,该信号用于子进程结束或停止时,通知父进程其子进程的状态改变。父进程可以通过捕获此信号来调用 wait()waitpid() 函数,以获取子进程的退出状态并回收资源。这有助于防止僵尸进程的产生,确保资源得到有效管理。

源码

main.cc

#include <iostream>
#include <string>
constexpr int CMDMAXSIZE = 1024;
void eval(const char *cmdline);
void shell() {char cmdline[CMDMAXSIZE] = {0};while (1) {std::cout << ">";// 读取stdin输入的命令行if (!fgets(cmdline, sizeof(cmdline), stdin)) {// 判断是否输入到文件尾if (feof(stdin))exit(0);}// 解析命令行并执行命令eval(cmdline);}
}int main() {shell();return 0;
}

eval.cc

该文件用于解析命令后执行命令

#include <iostream>
#include <signal.h>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
constexpr int ARGSIZE = 1024;//解析命令并将其存储到argv,并返回该命令是一个后台命令
int parseline(const char *command, char **argv);
// 判断是否是一个shell内置命令,如果是就直接执行,否则返回false
int inlinecommand(char **argv);
// 后台回收进程
void backprogrom(int sig);void eval(const char *cmdline) {if (!cmdline)return;char *argv[ARGSIZE] = {0};// 解析命令并判断是否是后台命令int bg = parseline(cmdline, argv);if (bg == -1)return;// 判断是否是shell内置命令,如果是就直接执行,并返回标志int flag = inlinecommand(argv);if (flag == -1)return;pid_t pid;// 判断是否是shell内置命令,如果是就处理内置命令,否则说明是一个可执行文件if (!flag) {// 无论是不是后台命令,都执行可执行文件if ((pid = fork()) == 0) {if (execve(argv[0], argv, environ) < 0) {std::cerr << "exec failed!" << std::endl;_exit(1);}} else if (pid > 0) {if (!bg) {// 如果不是后台命令,父进程需要阻塞等待子进程(也就是命令行)的执行wait(nullptr);} else if (bg > 0) { //如果是后台命令,父进行不需要阻塞等待子进程执行结束std::cout << "pid [" << pid << "] " << argv[0] << " running..."<< std::endl;signal(SIGCHLD, backprogrom);}}}
}

parseline.cc

该文件负责解析命令行及其选项,并返回判断是否为后台命令

#include <sstream>
#include <string>
#include <vector>
int parseline(const char *command, char **argv) {std::stringstream cmdline(command);std::vector<std::string> argv_vec;std::string cmd;while (cmdline >> cmd) {argv_vec.emplace_back(cmd);}if (argv_vec.empty())return -1;int argc = 0;for (auto &str : argv_vec) {argv[argc++] = const_cast<char *>(str.c_str());}if (argv_vec[argv_vec.size() - 1] == "&") {argv[argc - 1] = nullptr;return 1;}argv[argc] = nullptr;return 0;
}

inlinecommand.cc

该文件用于判断输入的命令是否是shell的内置命令,如果是就直接执行之

#include <iostream>
#include <stdlib.h>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unordered_set>
constexpr int CMDMAXSIZE = 1024;static std::unordered_set<std::string> inlinecmd = {"ls", "pwd", "clear"};int inlinecommand(char **argv) {std::string cmd(argv[0]);if (cmd == "exit") {exit(1);}auto it = inlinecmd.find(cmd);if (it != inlinecmd.end()) {pid_t pid = fork();if (pid == 0) {if (execvp(cmd.c_str(), argv) < 0) {std::cout << argv[0] << " exec error!" << std::endl;}}return 1;}return 0;
}

backwait.cc

该文件用于回收后台命令所在的子进程的资源

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
/*
1. exit
库:exit 定义在 <stdlib.h> 中。
功能:exit 在程序终止时会执行以下操作:调用所有已注册的 atexit 函数。刷新标准 I/O 缓冲区,确保所有数据都被写入。返回控制给操作系统,返回值为 exit 的参数。
适用场景:通常用于正常退出程序。
2. _exit
库:_exit 定义在 <unistd.h> 中。
功能:_exit 直接终止进程,不执行任何清理操作:不调用 atexit 函数。不刷新 I/O 缓冲区。直接将控制权返回给操作系统,返回值为 _exit 的参数。
适用场景:通常在子进程中使用,如在fork后立即退出,以避免在父进程和子进程之间共享未刷新缓冲的数据。
*/
ssize_t sio_puts(const char s[]) { return write(STDOUT_FILENO, s, strlen(s)); }
void sio_error(const char s[]) {sio_puts(s);return _exit(1);
}void backprogrom(int sig) {int olderrno = errno;while (waitpid(-1, nullptr, WNOHANG) > 0) {sio_puts("reaped child\n");}if (errno != ECHILD)sio_error("wait_pid error!");errno = olderrno;
}

测试效果

说明,本代码仅用于帮助理解shell执行命令的过程,但是对后台命令的处理稍显不足,并且对前台命令和后台命令的回收处理也仍旧需要改进,烦请大佬帮忙指正!

参考:《深入理解计算机系统》

【Linux】fork函数详解|多进程_多进程fork-CSDN博客

孤儿进程与僵尸进程[总结] - Rabbit_Dale - 博客园 (cnblogs.com)

 ​​​​​​孤儿进程与僵尸进程产生及其处理_孤儿进程的意义-CSDN博客

http://www.dtcms.com/wzjs/790183.html

相关文章:

  • 邮箱类网站模板开发大型网站的最主流语言
  • 网站优化入门免费教程折腾记录之WordPress熊掌号
  • 建站平台塔山双喜长沙网站建设价格
  • 医院网站优化fotor懒设计官网
  • 胖小七网站建设中学生做的网站有哪些
  • 石家庄网站建设seo网站开发的难点与重点
  • 辽宁省城乡建设厅官方网站深圳博纳网站建设
  • 兰州网站开发企业会计网站建设意义
  • 网上书城网站建设目的理财网站如何做推广
  • 做网站配置服务器京润珍珠企业网站优化
  • 鲜花网站建设的项目介绍福州网站建站
  • 怎么给网站加外链网站建设对教育解决方案
  • 佛山网站建设模板建站新网域名注册步骤
  • 手机上怎么做能打开的网站海外域名网站
  • 电商网站建设合同赣州市建设局
  • 网站排版设布局wordpress档案插件
  • wordpress怎么搜索网站网页游戏排行大全
  • 郑州网站建设 个人工作室wordpress获取当前分类id
  • 云南省建设注册考试中心网站百度网站建设流程
  • 制作网站价格站酷网官网
  • 优化网站步骤二手交易网站开发
  • 做公司网站解析上海十大好厂
  • 寄生虫网站排名代做怎么上传文章网站
  • 北京网站建设技术部服务器维护通知
  • 网站建设有些什么流程长沙网站开发哪家好
  • 怎么建设网站网站网站怎样制作 优帮云
  • 做养殖推广什么网站好河南开展涉网暴力专项举报工作
  • 直接用源码做网站盗版吗58徐州网站建设
  • 响应式网站导航网站建设优化开发公司哪家好
  • 网站建设与管理学校如何做好品牌网站建设