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

《LINUX系统编程》笔记p8

信号集

由多个信号构成的一个数据集合(可以理解含有多个信号的数组)

信号集合的类型: sigset_t

操作信号集的函数

#include <signal.h>// 清空信号集内的全部信号,成功返回0,出错返回-1
int sigemptyset(sigset_t *set);// 设置(添加)全部信号到信号集内,成功返回0,出错返回-1
int sigfillset(sigset_t *set);// 添加某个信号signum到信号集,成功返回0,出错返回-1
int sigaddset(sigset_t *set, int signum);// 从信号集删除某个信号signum,成功返回0,出错返回-1
int sigdelset(sigset_t *set, int signum);// 判断某个信号signum是否在信号集 set 中。
// 在信号集中返回1, 不再返回0,出错返回-1。
int sigismember(const sigset_t *set, int signum);

信号屏蔽sigprocmask(2)

作用:设置屏蔽和解除屏蔽,当前代码段屏蔽信号集中的信号的中断。

#include <signal.h>/* Prototype for the glibc wrapper function */
成功返回0,出错返回-1,同时设置errno
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
// 参数: how: SIG_BLOCK 设置当前信号集阻塞信号。SIG_UNBLOCK 设置当前信号集从阻塞信号中删除。SIG_SETMASK 设置阻塞信号。
//  set 新的信号集
//  oldset 返回旧的信号集.

原子操作

示例:取银行存钱

步骤:

张三存钱
1. 银行确定钱数 x = 10000;
2. 查询你之前的钱数 money
3. 计算出最总的结果 result = money + x4. 修改这个结果。 money =  result。张三的女朋友给张三存钱
1. 银行确定钱数 x = 50;
2. 查询你之前的钱数 money
3. 计算出最总的结果 result = money + x
4. 修改这个结果。 money =  result。

sigprocmask 示例

#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>void sig_handle(int sig) {printf("收到信号:%d\n", sig);
}void do_important_thing(void) {int ret;printf("开始做重要的事情\n");ret = sleep(10);if (ret != 0) printf("此事情被中断打断.\n");printf("结束做重要的事情\n");
}int main(int argc, char * argv[]) {sigset_t newset; // 新的信号集sigset_t oldset; // 用于保存之前的旧的信号集printf("PID:%d\n", getpid());signal(SIGINT, sig_handle);sigemptyset(&newset); // 清空 newset;sigaddset(&newset, SIGINT); // 将  SIGINT加入信号集合// 设置屏蔽newset中的信号,如果发生,则处于阻塞状态sigprocmask(SIG_BLOCK, &newset, &oldset);do_important_thing();// 解除阻塞,恢复之前的屏蔽状态。sigprocmask(SIG_SETMASK, &oldset, NULL);printf("做其他的事情\n");sleep(10);printf("程序退出\n");return 0;
}

sigsuspend 函数

作用:临时设置信号屏蔽字的原子操作。

函数格式

#include <signal.h>int sigsuspend(const sigset_t *mask);

示例

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>void sig_handle(int sig) {printf("收到信号:%d\n", sig);
}void do_important_thing(void) {sigset_t temp_set;int ret;printf("开始做重要的事情\n");ret = sleep(5);if (ret != 0) printf("此事情被中断打断.\n");// 希望有信号就能够得到及时的响应。sigemptyset(&temp_set); // 清空sigsuspend(&temp_set); // 处理中断ret = sleep(5);if (ret != 0) printf("此事情被中断打断.\n");printf("结束做重要的事情\n");
}int main(int argc, char * argv[]) {sigset_t newset; // 新的信号集sigset_t oldset; // 用于保存之前的旧的信号集printf("PID:%d\n", getpid());signal(SIGINT, sig_handle);sigemptyset(&newset); // 清空 newset;sigaddset(&newset, SIGINT); // 将  SIGINT加入信号集合// 设置屏蔽newset中的信号,如果发生,则处于阻塞状态sigprocmask(SIG_BLOCK, &newset, &oldset);do_important_thing();// 解除阻塞,恢复之前的屏蔽状态。sigprocmask(SIG_SETMASK, &oldset, NULL);printf("做其他的事情\n");sleep(10);printf("程序退出\n");return 0;
}
abort 函数

abort函数

作用:让程序异常终止。

函数格式

#include <stdlib.h>void abort(void);

sigaction 函数

作用:代替signal 函数,让信号处理更可靠,并可以获取更多的信号信息,包括信号的发送进程ID等信息。

函数格式

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

进程间通信(IPC)

IPC(Inter-Process Communitation)

进程间通信的进程关系可以是如下几种

  1. 父子进程
  2. 拥有相同父进程的两个子进程。
  3. 无亲缘关系的进程。

相关内容 《APUE》第十五章

UNIX 进程间通信的机制

  • 信号

  • 管道

    • 匿名管道(PIPE)
    • 有名管道(FIFO)
  • XSI IPC

    • 消息队列(Message Queue)
    • 信号量数组(semaphore Array)
    • 共享内存(Shared Memory)

管道

管道是Linux 内核中的一段内存,类似于循环队列,一个管道可以存储一段数据信息

创建管道的打开方式

int pipe(int fds[2]);
单工
| 进程1 |   ---->  | 进程2 |半双工(同一时刻只能一个方向传递数据)
| 进程1 |   -->--<-- | 进程2 |全双工
+ ---- +            +-------+
| 进程1 |   ----->   | 进程2 |
+ ---- +   <------- +-------+

管道的写操作 write(2)

  • write(fd[1]) 写管道的1端,写满会阻塞。

管道的读操作 read(2)

  • read(fd[0]) 读管道的0端,读空时会阻塞

管道容量

65536字节,默认是16个页(page),每个页4K。

管道发送的信号

管道读取端关闭,写管道会出发SIGPIPE信号。如果进程忽略此信号。则write(2) 返回-1并设置 errno为 EPIPE。

管道写端关闭,读取是read(2) 返回0.

示例代码

#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>void wait_child(int sig) {int status;pid_t pid;pid = wait(&status);printf("进程 pid: %d已经回收\n", pid);
}
void sig_handle(int sig) {printf("sig:%d\n", sig);
}int main(int argc, char * argv[]) {int fds[2];  // 用户存储管道打开的文件描述符int ret;char buf[1024];pid_t pid;signal(SIGPIPE, sig_handle);signal(SIGCHLD, wait_child);ret = pipe(fds); // 打开管道if (-1 == ret) {perror("pipe");return 1;}pid = fork();if (pid == -1) {perror("fork");return 2;}if (0 == pid) {close(fds[1]); // 关闭写端while(1) {ret = read(fds[0], buf, 1024);printf("ret:%d\n", ret);buf[ret] = 0;printf("buf:%s\n", buf);if (0 == strcmp(buf, "exit")) {close(fds[0]);return 0;}}}close(fds[0]); // 关闭读端while(1) {printf("请输入文字:");fflush(NULL); // 清空所有缓冲区。ret = read(0, buf, 1024); // "abc\n"buf[ret-1] = 0;write(fds[1], buf, ret-1);// if (0 == strcmp(buf, "exit")) {//     close(fds[1]);//     break;// }}printf("程序退出\n");return 0;
}
http://www.xdnf.cn/news/19830.html

相关文章:

  • 大模型RAG项目实战:RAG技术原理及核心架构
  • SpringBoot 事务管理避坑指南
  • 机器学习:从技术原理到实践应用的深度解析
  • 机器人抓取中的力学相关概念解释
  • JVM中产生OOM(内存溢出)的8种典型情况及解决方案
  • 初识NOSQL
  • 方法决定效率
  • git: 取消文件跟踪
  • SRE团队是干嘛的
  • 关于IDE的相关知识之一【使用技巧】
  • Spring Security 如何使用@PreAuthorize注解
  • Nano Banana 新玩法超惊艳!附教程案例提示词!
  • AI 设计工具天花板
  • 【android bluetooth 协议分析 21】【ble 介绍 3】【ble acl Supervision Timeout 介绍】
  • 黑马头条面试重点业务
  • 构建下一代智能金融基础设施
  • SpringBoot--手写日期格式转换工具类
  • TiDB v8.5.3 单机集群部署指南
  • ASP.NET Core上传文件到minio
  • 【leetcode】236. 二叉树的最近公共祖先
  • 利用Base64传输二进制文件并执行的方法(适合没有ssh ftp等传输工具的嵌入式离线场景)
  • 研发文档版本混乱的根本原因是什么,怎么办
  • ELK 统一日志分析系统部署与实践指南(上)
  • 撤销修改 情况⼀:对于⼯作区的代码,还没有 add
  • 餐饮、跑腿、零售多场景下的同城外卖系统源码扩展方案
  • 图片移到根目录
  • Spring Boot + Spring MVC 项目结构
  • ARM汇编记忆
  • C# 简述委托,Func与Action委托。 他们之前有什么区别?
  • 告别手动复制粘贴:C# 实现 Excel 与 TXT 文本文件高效互转