IO进程(学习)2024.8.22

news2025/1/10 20:25:46

信号

信号函数

信号处理函数

#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
功能:信号处理函数
参数:signum:要处理的信号
           handler:信号处理方式
                        SIG_IGN:忽略信号
                        SIG_DFL:执行默认操作
                        handler:捕捉信号  
                         void handler(int sig){} //函数名可以自定义
返回值:成功:设置之前的信号处理方式
               失败:-1

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    if (sig == SIGQUIT)
    {
        printf("是SIGQUIT信号\n");
    }
    else
    {
        printf("是其他信号\n");
    }
}

int main(int argc, char const *argv[])
{
    // signal(SIGINT, SIG_DFL); // 执行默认操作

    // signal(SIGINT, SIG_IGN); // 忽略信号

    signal(SIGINT, handler); // 捕捉信号

    pause();
    return 0;
}

信号的处理过程

程序运行在用户空间时->进程由于系统调用或中断进入内核->转向用户空间执行信号处理函数->信号处理函数完毕后进入内核->返回用户空间继续执行程序

练习:用信号的知识实现司机和售票员问题。
1.售票员捕捉SIGINT(代表开车)信号,向司机发送SIGUSR1信号,司机打印(let's gogogo)
2.售票员捕捉SIGQUIT(代表停车)信号,向司机发送SIGUSR2信号,司机打印(stop the bus)
3.司机捕捉SIGTSTP(代表到达终点站)信号,向售票员发送SIGUSR1信号,售票员打印(please get off the bus)
4.司机等待售票员下车,之后司机再下车。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

pid_t pid;  // 售票员的进程ID
pid_t ppid; // 司机的进程ID

// 售票员的信号处理函数
void shoupiaoyuan(int sig)
{
    if (sig == SIGINT)
    {
        kill(ppid, SIGUSR1); // 向司机发送SIGUSR1信号
    }
    if (sig == SIGQUIT)
    {
        kill(ppid, SIGUSR2); // 向司机发送SIGUSR2信号
    }
    if (sig == SIGUSR1)
    {
        printf("Please get off the bus!\n");
        exit(0);
    }
}

// 司机的信号处理函数
void siji(int sig)
{
    if (sig == SIGUSR1)
    {
        printf("Let's gogogo!\n");
    }
    if (sig == SIGUSR2)
    {
        printf("Stop the bus!\n");
    }
    if (sig == SIGTSTP)
    {
        kill(pid, SIGUSR1); // 向售票员发送SIGUSR1信号
        wait(NULL);
        exit(0);
    }
}

int main()
{
    ppid = getpid();
    pid = fork();
    if (pid < 0)
    {
        perror("forka创建失败");
        return -1;
    }

    if (pid == 0) // 子进程:售票员
    {
        // 等待信号
        while (1)
        {
            signal(SIGTSTP, SIG_IGN);      // 忽略SIGTSTP信号
            signal(SIGINT, shoupiaoyuan);  // 捕捉信号SIGINT
            signal(SIGQUIT, shoupiaoyuan); // 捕捉信号SIGQUIT
            signal(SIGUSR1, shoupiaoyuan); // 捕捉信号SIGUSR1
            pause();
        }
    }
    else // 父进程:司机
    {
        // 等待信号
        while (1)
        {
            signal(SIGINT, SIG_IGN);  // 忽略SIGINT
            signal(SIGQUIT, SIG_IGN); // 忽略SIGQUIT
            signal(SIGUSR1, siji);    // 捕捉信号SIGUSR1
            signal(SIGUSR2, siji);    // 捕捉信号SIGUSR2
            signal(SIGTSTP, siji);    // 捕捉信号SIGTSTP
            pause();
        }
    }
    return 0;
}

共享内存

概念

共享内存指的是操作系统在物理内存中申请一块空间,应用程序可以映射到这块空间,进行直接读写操作

特点

1.共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
2.为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间
3.进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率
4.由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等

步骤

1.创建唯一key值        ftok
2.创建或打开共享内存        shmget
3.映射共享内存        shmat
4.取消映射        shmdt
5.删除共享内存        shmctl

函数接口

创建key值

#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
功能:创建key值
参数:pathname:文件名
           proj_id:取整型数的低8位数值(一般是写一个字符 'a')
返回值:成功:key值
              失败:-1
key值是根据pathname的inode号和proj_id的低8位组合而成的。

 

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>

int main(int argc, char const *argv[])
{
    key_t key;
    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    printf("key值为:%#x\n", key);
    return 0;
}

创建或打开共享内存

#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
功能:创建或打开共享内存
参数:
        key  键值
        size   共享内存的大小
                             创建         检测错误
        shmflg   IPC_CREAT | IPC_EXCL | 0666  创建共享内存的时候的权限
返回值:成功   shmid  共享内存的id
              出错    -1

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid;
    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 64, 0666);
        }
        else
        {
            perror("创建共享内存失败");
            return -1;
        }
    }
    printf("%d\n", shmid);

    return 0;
}

映射共享内存

void  *shmat(int  shmid,const  void  *shmaddr,int  shmflg);
功能:映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
参数:
        shmid   共享内存的id号
        shmaddr   一般为NULL,表示由系统自动完成映射
                         如果不为NULL,那么有用户指定
        shmflg:SHM_RDONLY就是对该共享内存只进行读操作
                                0        可读可写
返回值:成功:完成映射后的地址,
               出错:(void *)-1的地址

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid;
    char *p;

    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    printf("key值为:%#x\n", key);

    shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 64, 0666);
        }
        else
        {
            perror("创建共享内存失败");
            return -1;
        }
    }
    printf("shmid号为:%d\n", shmid);

    p = shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }

    strcpy(p, "hello");
    printf("%s\n", p);

    return 0;
}

取消映射

int shmdt(const void *shmaddr);
功能:取消映射
参数:要取消的地址
返回值:成功:0  
               失败:-1

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid;
    char *p;

    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    printf("key值为:%#x\n", key);

    shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 64, 0666);
        }
        else
        {
            perror("创建共享内存失败");
            return -1;
        }
    }
    printf("shmid号为:%d\n", shmid);

    p = shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }

    strcpy(p, "hello");
    printf("%s\n", p);
    
    // 阻塞观察内存状态
    // getchar();

    // 取消映射
    shmdt(p);

    return 0;
}

删除共享内存

int  shmctl(int  shmid,int  cmd,struct  shmid_ds   *buf);
功能:(删除共享内存),对共享内存进行各种操作
参数:
        shmid   共享内存的id号
        cmd     IPC_STAT 获得shmid属性信息,存放在第三参数
                    IPC_SET 设置shmid属性信息,要设置的属性放在第三参数
                    IPC_RMID:删除共享内存,此时第三个参数为NULL即可
        struct  shmid_ds   *buf:是一个结构体指针,但我们是删除共享内存,所以并没有意义,我们直接设置为NULL就可以了
返回:成功0 
           失败-1

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    key_t key;
    int shmid;
    char *p;

    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    printf("key值为:%#x\n", key);

    shmid = shmget(key, 64, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 64, 0666);
        }
        else
        {
            perror("创建共享内存失败");
            return -1;
        }
    }
    printf("shmid号为:%d\n", shmid);

    p = shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }

    strcpy(p, "hello");
    printf("%s\n", p);

    // 阻塞观察内存状态
    // getchar();

    // 取消映射
    shmdt(p);

    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

操作命令

ipcs -m:查看系统中创建的共享内存
ipcrm -m shmid:删除创建的共享内存

练习:通过共享内存实现进程间通信,一个进程从终端输入数据(input.c),另一个进程打印数据(output.c),循环执行,当输入quit时循环结束

input.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>

struct data
{
    int flag;
    char buf[32];
};

int main()
{
    key_t key;
    int shmid;
    struct data *p = NULL;

    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    printf("key值为:%#x\n", key);

    shmid = shmget(key, 64, IPC_CREAT | 0666);
    if (shmid < 0)
    {
        perror("创建共享内存失败");
        return -1;
    }
    printf("shmid号为:%d\n", shmid);

    p = (struct data *)shmat(shmid, NULL, 0);
    if (p == (struct data *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }
    p->flag = 0;
    while (1)
    {
        scanf("%s", p->buf);
        p->flag = 1;
        if (strcmp(p->buf, "quit") == 0)
        {
            break;
        }
    }
    shmdt(p);
    return 0;
}

output.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
struct data
{
    int flag;
    char buf[32];
};

int main()
{
    key_t key;
    int shmid;
    struct data *p = NULL;

    key = ftok("./test", 'a');
    if (key < 0)
    {
        perror("创建key值失败");
        return -1;
    }
    printf("key值为:%#x\n", key);

    shmid = shmget(key, 64, 0666);
    if (shmid < 0)
    {
        perror("获取共享内存失败");
        return -1;
    }
    printf("shmid号为:%d\n", shmid);

    p = (struct data *)shmat(shmid, NULL, 0);
    if (p == (struct data *)-1)
    {
        perror("映射共享内存失败");
        return -1;
    }
    p->flag = 0;
    while (1)
    {
        if (p->flag == 1)
        {
            if (strcmp(p->buf, "quit") == 0)
            {
                break;
            }
            printf("读取到的数据: %s\n", p->buf);
            p->flag = 0;
        }
    }
    shmdt(p);
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于矢量控制器的PMSM永磁同步电机速度控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于矢量控制器的PMSM永磁同步电机速度控制系统simulink建模与仿真&#xff0c;仿真输出电机转速跟踪曲线&#xff0c;PID控制器输出曲线以及Te输出曲线。 2.系统仿真结果 &…

kafka的一个有趣问题(BUG)

这是我的第104篇原创文章 问题由来 在使用kafka时&#xff0c;创建topic&#xff0c;对某个topic进行扩分区的操作&#xff0c;想必大家肯定都使用过。尤其是集群进行扩容时&#xff0c;对流量较大的topic进行扩分区操作。一般而言&#xff0c;期望的效果是&#xff1a;新扩的分…

AI在医学领域:HYDEN一种针对医学图像和报告的跨模态表示学习方法

近年来&#xff0c;跨模态文本-图像表示学习在诸多领域取得了显著的突破&#xff0c;尤其是在零样本学习和图像-文本检索等任务上。这一成果的取得很大程度上归功于大量弱监督的图像-文本配对数据的利用&#xff0c;这些数据有效地增强了视觉-语言表示学习的能力。在医学成像领…

如何保证每次生成的都同一张人脸?AI绘画Stable Diffusion的Reference only插件人物一致性教程

Ai绘画有一个很现实的问题&#xff0c;要保证每次画出的都是同一个人物的话&#xff0c;很费劲。 Midjourney就不必说了&#xff0c;人物的高度一致性一直得不到很好的解决。而在Stable Diffusion&#xff08;SD&#xff09;中&#xff0c;常用办法是通过同一个Seed值&#xf…

Linux宝塔面板使用教程 - Centos/Alibaba Cloud Linux,解放命令实现可视化

使用前注意事项&#xff1a;为了您的正常使用&#xff0c;请确保使用全新或纯净的系统安装宝塔面板&#xff0c;不支持已部署项目/环境的系统安装 1.安装命令 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh &&…

Godot《躲避小兵》实战之创建游戏主场景

游戏主场景 现在是时候将我们所做的一切整合到一个可玩的游戏场景中了。 创建新场景并添加一个 Node节点&#xff0c;命名为 Main。&#xff08;我们之所以使用 Node 而不是 Node2D&#xff0c;是因为这个节点会作为处理游戏逻辑的容器使用。本身是不需要 2D 功能的。&#x…

ZooKeeper 的3种部署模式

ZooKeeper 的3种部署模式 1. 单机模式&#xff08;Standalone Mode&#xff09;2. 伪集群模式&#xff08;Pseudo-Cluster Mode&#xff09;3. 集群模式&#xff08;Cluster Mode&#xff09; &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496;…

[000-01-011].第2节:持久层方案的对比

我的后端学习大纲 MyBatis学习大纲 1.持久层解决方案&#xff1a; 1.1.面试1&#xff1a;请说一说持久层解决方案有哪些&#xff1f;&#xff1f;&#xff1f; 1.jdbc JDBC为访问不同的数据库提供了一种统一的途径&#xff0c;为开发者屏蔽了一些细节问题。Java程序员使用JDB…

Vodafone 推出了与 Wi-Fi 竞争的基于树莓派私人5G技术

随着全球5G网络的逐步推出&#xff0c;在其过程中遇到了可预见的起起伏伏&#xff0c;并且蜂窝技术也开始进入另一个无线技术 Wi-Fi &#xff0c;并且已经占据的市场。私有5G网络&#xff08;即个人或公司建立自己的全设施蜂窝网络&#xff09;如今正在寻找曾经属于Wi-Fi的唯一…

Unity低延迟播放RTSP视频流

Unity播放RTSP视频流这个功能在好几个项目中用到&#xff0c;虽然有一些现成的插件&#xff08;VLC for unity、UMP&#xff09;可以使用&#xff0c;但是延迟高&#xff08;300毫秒以上&#xff09;的问题一直没法解决。 最近终于下定决心来解决这个问题&#xff0c;经过几天…

基于 Jenkins、Gitlab、Harbor、Helm 和 Kubernetes 的 CI/CD

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

【微服务部署】Linux部署微服务启动报ORA-01005

问题背景&#xff1a; Linux机器部署springboot微服务&#xff0c;部署完成后发现无法启动&#xff0c;后台报ORA-01005错误。 解决方案&#xff1a; 1.检查当前服务器是否已安装oracle客户端 命令行执行sqlplus username/passwd实例名&#xff0c;如果执行成功&#xff0c;说…

【Canvas与艺术】十边曲线形光阑

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>十边曲线型光阑</title><style type"text/css"&g…

机器学习-识别手写数字

机器学习可以首先构建一个神经网络&#xff0c;用于识别手写数字。通过训练数据&#xff0c;优化神经网络的参数。再利用测试数据来测试训练完成后的神经网络的准确度。本次需要下载的库有tensorflow和matplotlib&#xff0c;keras和mnist数据集一般都被集成在tensorflow中了。…

C/C++语言基础--指针三大专题详解3,完结篇(包括指针做函数参数,函数指针,回调函数,左右法则分析复杂指针等)

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 指针是C/C的灵魂&#xff0c;和内存地址相关联&#xff0c;运行的时候速度快&#xff0c;但是同时也有很多细节和规范要注意的&#xff0c;毕竟内存泄漏是很恐怖的指针打算分三篇文章进行讲解&#xff0c;本…

LabVIEW多显示器环境下主显示器识别与管理

该程序使用 LabVIEW 图形化编程语言&#xff0c;涉及多显示器环境中主显示器的识别与信息提取。图像显示了两个不同的方法来获取主显示器的信息。 第一部分&#xff1a;方法一——基于显示器位置的主显示器识别 1. 当前监视器识别&#xff1a; 使用“FP.Monitor”属性节点获取…

在AES加密中,设主密钥为“2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C”,试计算迭代第1轮使用的轮密钥。

题解: 1.分析: 第一轮使用的轮密钥是W[4]、W[5]、W[6]、W[7] w[i](4≤i≤43)求法: (1)i不为4的倍数 w[i] = w[i-1] ⊕w[i-4] (2)为4的倍数 w[i]=SubWord(RotWord(w[i-1]))⊕w[i-4]⊕Rcon[i/4] 解释: ①RotWord:将w[i-1]的4个字节循环上移一个字节 ②SubWo…

JVM的类是如何运行的

本文就是讲解 如何将.class文件转换为机器码

U盘中毒文件被隐藏怎么恢复文件?

很多用户都曾经遇到过U盘文件被病毒隐藏的问题&#xff0c;U盘作为拷贝、存储文件最主要的移动存储设备&#xff0c;里面经常存储了重要的文件&#xff0c;如果文件被隐藏了会给用户带来很多麻烦。那么U盘文件被病毒隐藏&#xff0c;应该怎么解决呢&#xff1f;本文列举了有效的…

QT中使用QAxObject类读取xlsx文件内容并显示在ui界面

一、源码 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr);~MainWindow();pr…