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

日期:2025.1.26(凌晨)

学习内容:

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

Linux的信号

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

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

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

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

cpp
#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_signal
    signal(SIGINT, handle_signal);

    // 等待信号的到来
    while (1) {
        printf("Running...\n");
    }

    return 0;
}

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

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

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

另外还有一些宏定义是:

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

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

另外关于函数指针:

cpp
#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了时候,会去执行之前使用过的(即放在参数里的)函数。

cpp
#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函数的参数讲起来比较麻烦,直接上代码。

cpp
#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就是把参数都放到数组里面。(但是第一个参数还是要写的)

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

创建进程

cpp
#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:

arduino
#include <fstream>
#include <iostream>

int main() {
    // 创建一个 ofstream 对象
    std::ofstream outFile;

    // 打开文件
    outFile.open("example.txt");

    // 写入数据
    outFile << "Hello, World!" << std::endl;

    // 关闭文件
    outFile.close();

    return 0;
}

ifstream:

arduino
#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:

arduino
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;
}

__EOF__

  • 本文作者: AdviseDY
  • 本文链接: https://www.cnblogs.com/advisedy/p/18691455
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 除特殊说明外,转载请注明出处~[知识共享署名-相同方式共享 4.0 国际许可协议]
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • posted @   AdviseDY  阅读(17)  评论(1编辑  收藏  举报
    相关博文:
    阅读排行:
    · DeepSeek-R1本地部署如何选择适合你的版本?看这里
    · 开源的 DeepSeek-R1「GitHub 热点速览」
    · 传国玉玺易主,ai.com竟然跳转到国产AI
    · 揭秘 Sdcb Chats 如何解析 DeepSeek-R1 思维链
    · 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
    点击右上角即可分享
    微信分享提示