【Linux】信号|进程终止|调用可执行程序|创建进程 学习笔记

news/2025/1/27 7:11:30/文章来源:https://www.cnblogs.com/advisedy/p/18691455

日期:2025.1.26(凌晨)

学习内容:

  • Linux的信号
  • 进程终止
  • 调用可执行程序
  • 创建进程

Linux的信号

首先要知道,我们是可以向进程发送信号的。

要么是直接键盘上发出命令(ctrl + c),或者是利用kill命令。

kill命令
主要是两个命令:kill和killall命令。
kill命令是要加上pid,而killall命令是要加上进程的名字。
选项默认的是发出一个SIGTERM(15)命令,用于终止。
-9是强制终止。

而在信号的处理上,我们可以修改原本信号的处理器,使得处理信号自定义。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 定义一个信号处理器函数
void handle_signal(int sig) {printf("Received signal %d\n", sig);//signal(sig, SIG_DFL); // SIG_DFL恢复信号的默认处理方式
}int main() {// 设置 SIGINT (通常是 Ctrl+C) 的处理器为 handle_signalsignal(SIGINT, handle_signal);// 等待信号的到来while (1) {printf("Running...\n");}return 0;
}

上述代码中,修改了\(SIGINT\)的信号处理,变成了输出一段话。

在这里中,使用了回调函数。就像这个signal函数中,第二个参数是函数指针,像这种参数是函数指针的,一般就称为回调函数。而这个函数指针对应的函数的参数,是自动接收了信号对应的数字(因为信号SIGINT就是一个宏,其实是一个数字)。

这个signal函数是用来修改信号的处理方式的。可以理解为,当执行到这个函数时,会将SIGINT的处理变成了调用这个函数。如果将注释的内容去掉的话,那么执行第一次之后,处理方式会变成了默认处理方式。

另外还有一些宏定义是:

  • SIG_IGN(忽略该信号)
  • SIGSHLD(杀死子进程)

还有是killall -0,这个选项可以判断出进程是否还存活。

另外关于函数指针:

#include <iostream>
#include <string>
using namespace std;int myTest(int a, string b)
{cout << "a = " << a << " b = " << b << endl;return 123;
}using func = int(*)(int, string);int main()
{func f = myTest;int a=f(10, "hello");int b = (*f)(10, "hello");cout << a << endl;cout << b << endl;return 0;
}

以上代码中两个调用函数的方式,没有区别。

进程终止

主要是关于exit函数的应用。包括(_exit,_Exit,atexit)函数。

exit这些函数的参数都代表着进程结束时的状态,0代表正常,非0代表不正常。

要注意的点是,析构函数在exit函数使用了之后,只会触发全局变量的析构函数,而不会触发局部变量的析构函数。(插一句,正常return是会触发局部变量的析构,main函数的return会触发全局变量的析构)。而_exit,_Exit函数是都不触发。

atexit函数的参数是函数指针,最多使用32次。

代表当程序exit了时候,会去执行之前使用过的(即放在参数里的)函数。

#include <stdio.h>
#include <stdlib.h>// 定义一个清理函数
void cleanup1() {printf("Cleanup 1: Releasing resources...\n");
}void cleanup2() {printf("Cleanup 2: Saving state...\n");
}int main() {// 注册清理函数atexit(cleanup1);atexit(cleanup2);exit(0);printf("Program is running...\n");// 正常退出return 0;
}

这里的输出是先输出cleanup2的内容,再输出1的内容。(倒着的)

调用可执行程序

主要是有system,execl,execv函数。后者两个很像,会简单概括。

system的参数是const char *,里面放的就是命令。

而execl函数的参数讲起来比较麻烦,直接上代码。

#include <unistd.h>
#include <stdio.h>int main() {// 使用 execl 执行 /bin/ls 命令execl("/bin/ls", "ls", "-l", NULL);// 如果 execl 成功,不会执行下面的代码printf("This line will not be executed if execl is successful.\n");return 0;
}

如图,第一个参数是命令的路径,第二个是命令本身的名称,当然放路径也是可以的,也就是说第一个参数和第二个参数一模一样,然后后面可以加上选项。结尾用0或者NULL。

要注意的是,使用了execl函数后,会开启一个新的进程,而这个进程会代替现在的进程,取代了数据段和堆栈。

execv就是把参数都放到数组里面。(但是第一个参数还是要写的)

int main() {char* argv[10];argv[0] = (char*)"/bin/ls";argv[1] = (char *)"-l";argv[2] = 0;execv("/bin/ls",argv);return 0;
}

创建进程

#include <unistd.h>
#include <stdio.h>
int main() {pid_t pid = getpid();pid_t ppid = getppid();return 0;
}

第一个是获取当前进程的pid,第二个是获取当前进程的父进程的pid。

类型是pid_t,宏定义,原本是int。

fork函数:

用来创建一个子进程的,返回值是有两个。

在当前进程的返回值是当前进程的pid,而在子进程的返回值是0。(根据这个可以判断出来当前是子进程还是进程)。

在使用了这个函数之后,之后的部分就可以理解成会跑两遍。所以像文件ofstream类,要在调用fork函数之前就使用,这样就能够实现两个进程跑的内容是共有的而不是重叠的。

ofstream:

#include <fstream>
#include <iostream>int main() {// 创建一个 ofstream 对象std::ofstream outFile;// 打开文件outFile.open("example.txt");// 写入数据outFile << "Hello, World!" << std::endl;// 关闭文件outFile.close();return 0;
}

ifstream:

#include <fstream>
#include <iostream>
#include <string>int main() {std::ifstream inFile("example.txt");if (inFile.is_open()) {std::string line;while (getline(inFile, line)) {std::cout << line << std::endl;}inFile.close();} else {std::cerr << "Unable to open file" << std::endl;}return 0;
}

fstream:

std::fstream file("example.txt", std::ios::in | std::ios::out | std::ios::app);
if (file.is_open()) {file << "Appending text to file." << std::endl;file.seekg(0); // 移动到文件开头std::string line;while (getline(file, line)) {std::cout << line << std::endl;}file.close();
} else {std::cerr << "Unable to open file" << std::endl;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/875815.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入探讨数据库索引类型:B-tree、Hash、GIN与GiST的对比与应用

title: 深入探讨数据库索引类型:B-tree、Hash、GIN与GiST的对比与应用 date: 2025/1/26 updated: 2025/1/26 author: cmdragon excerpt: 在现代数据库管理系统中,索引技术是提高查询性能的重要手段。当数据量不断增长时,如何快速、有效地访问这些数据成为了数据库设计的核…

玩转单例模式

Java中单例(Singleton)模式是一种广泛使用的设计模式。单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。一些管理器和控制器常被设计成单例模式。 单例模式的好处:能够避免实例对象的重复创建,不仅可以减少每次创建对象的时间开销,还可以节约内存空间; 能够…

佳能EOS888说明书

这回讲佳能EOS888,EOS 888/EOS 5000于1995年元月推出,原来主要是面向东南亚市场,“888”就是取“发发发”的谐音。后来受到用户喜爱,于是就以EOS 5000的型号推向国际市场。 先贴个规格参数由于某文库某丁网某人的说明书需要付费下载,并且缺39页,找了英文版的39页补全。 说…

处理nginx解析跳转的域名不是最新的ip问题

我的场景是这样的,使用了贝锐的ddns服务,但是服务器上的nginx配置的域名解析不到最新的ip地址 问题如下我的贝锐域名可以打开,但是这里显示的不是最新的ip地址 在nginx.conf配置文件中加入resolver 223.5.5.5 223.6.6.6 valid=60s; 这里表示缓存的时间是60秒

【模拟电子技术】15-Q点稳定的放大电路和基本共集放大电路

【模拟电子技术】15-Q点稳定的放大电路和基本共集放大电路增加RE抑制温漂增加RB2并使得经过它的电流很大,分压大,使得静态工作点趋于稳定但是RE电阻在交流通路中会使得放大倍数减小(即使我们分析输入电阻,得到输入电阻增加了,但是我们还是希望得到一个高放大倍数的电路)于…

【AI+零售】构建一个有智能体参与的去中心化RWA零售生态系统商业模型

# 零售行业 在零售行业中,传统中心化模式因信息不对称、效率低下和利益分配不公平等问题逐渐暴露其局限性。而随着区块链、人工智能(AI)和智能体(Agent)技术的发展,去中心化零售生态系统成为可能。本文将系统性地探讨如何构建一个有智能体深度参与的去中心化零售商业模型…

《CPython Internals》阅读笔记:p356-p359

《CPython Internals》学习第 19天,p356-p359 总结,总计 4 页。 一、技术总结 1.benchmark suite The benchmark suite is the tool to use when comparing the complete performance of Python. The Python Benchmark suite is a collection of Python applications design…

昆工昆明理工大学材料25调剂名额

--材测材料物理与化学材料学材料表征与分析材料工程F001现代材料测试技术F002材料成型技术基础864材料科学基础

@FeignClient中configuration属性的简单介绍

第一个控制请求的日志打印级别 先看效果图 日志级别配置方式新增类 public class FeignConfig {/*** NONE【性能最佳,适用于生产】:不记录任何日志(默认值)* BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间* HEADERS:记录BASIC级别的基…

【MySQL】Mysql 加锁机制与死锁分析

一、锁的分类1.1 锁模式1.2 锁粒度1.2.1 全局锁1.2.2 表级锁1.2.3 页级锁1.2.4 行锁1.3 锁范围1.3.1 记录锁1.3.2 间隙锁(Gap)1.3.3 临键锁1.3.4 意向锁(IS、IX)1.4 兼容性二、加锁机制2.1 加锁规则2.2 加锁分析2.2.1 无索引等值查询2.2.2 无索引范围查询2.2.3 无索引未命中…

Linux上安装DVWA,小白也能上手

dvwa是什么? dvwa全称是Damn Vulnerable Web Application,自己翻译吧。 它是一款非常实用的Web应用安全学习和测试平台。那我就在linux上安装下看看。 对了,我这里的linux是centos 7。 首先,dvwa需要什么? 1、数据库:mysql 2、web服务器:我这里选的是apache,而且php还要…

关于pushup与pushdown的几种常见情况

适用于线段树、平衡树等树形结构。 一.区间修改,区间求和(求最值) 二.最大连续子序列 这里有一种类似于 \(DP\) 的方法。 对于一个节点 \(Rt\),我们需要维护四个值。\(sum\) : 此区间的总和。 \(lmx\) : 此区间从左边开头的最大连续子序列。 \(rmx\) : 此区间从右边开头的最…