linux 进程通信 C程序案例

news2025/7/19 14:38:53

linux 进程通信 C程序案例

编写C程序完成:父进程创建两个子进程,每个进程都在屏幕上显示自己的进程ID号,并在第1个子进程中加载执行一条外部命令。

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


int main(int argc, char const *argv[])
{
    pid_t c1 = fork();

    if(c1 == 0)          //child1
    {   
        printf("[%d] : child1\n", getpid());
        execl("/bin/sh", "sh", "-c", "date", (char *)0);
    }
    else if(c1 > 0)     //parent
    {   
        printf("[%d] : parent\n", getpid());
        pid_t c2 = fork();

        if(c2 == 0)     //child2
        {
            printf("[%d] : child2\n", getpid());
        }
        else if(c2 > 0)       //parent
        {   
            printf("[%d] : parent\n", getpid());
            int status;
            wait(&status);
        }
    }
    return 0;
}

在这里插入图片描述

编写C程序完成:父进程创建1个子进程,然后建立无名管道与子进程互相传递问候信息(父进程发出“hello!”,子进程发出“Hi!”),最后各自将接收到的信息输出到屏幕。

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

int main()
{
    char *parent_talk[] = {"hello",  NULL};
    char *child_talk[] = {"hi",  NULL};
    int fd1[2];
    int fd2[2];
    int res = pipe(fd1);
    if (res == -1)
    {
        printf("create pipe error.\n");
        exit(1);
    }
    res = pipe(fd2);
    if (res == -1)
    {
        printf("create pipe erroe.\n");
        exit(1);
    }
    pid_t pid;
    pid = fork();
    if (pid == 0) //子进程
    {
        close(fd1[1]); //子进程关闭fd1的写端,关闭fd2的读端
        close(fd2[0]);
        char buf[256];
        int i;
        char *talk = child_talk[i];
        while (talk != NULL)
        {
            sleep(5);
            read(fd1[0], buf, 256);
            printf("父进程:>%s\n", buf);
            write(fd2[1], talk, strlen(talk) + 1);
            i++;
            talk = child_talk[i];
        }
        close(fd1[0]);
        close(fd2[1]);
    }
    else if (pid > 0)
    {
        close(fd1[0]); //父进程关闭fd1的读端,关闭fd2的读端
        close(fd2[1]);

        char buf[256];
        int i = 0;
        char *talk = parent_talk[i];
        while (talk != NULL)
        {
            write(fd1[1], talk, strlen(talk) + 1);
            read(fd2[0], buf, 256);
            printf("子进程:>%s\n", buf);
            i++;
            talk = parent_talk[i];
        }
        close(fd1[1]);
        close(fd2[0]);
        int status;
        wait(&status);
    }
    return 0;
}

在这里插入图片描述

理解创建进程的系统调用并分析fork()与vfork()异同。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
    int data = 0;
    pid_t pid;
    int choose = 0;
    while ((choose = getchar()) != 'q')
    {
        switch (choose)
        {
        case '1':
            pid = fork();
            // fork的返回值,大于0 的时候,代表是父进程。此时的返回值,刚好是子进程的pid号
            // fork的返回值,等于0 的时候,代表的是子进程。此时的子进程的pid号其实是复制了fork大于0 的返回值。

            if (pid < 0)
                printf("Error !\n");
            if (pid == 0) // 子进程执行后+1
            {
                data++;
                exit(0);
            }
            wait(NULL);
            if (pid > 0)
                printf("data is %d\n", data); // 子进程未执行 ,为 0
            break;
        case '2':
            pid = vfork(); //  vfork():保证子进程先运行
            if (pid < 0)   // 出错
                perror("Error !\n");
            if (pid == 0) // 子进程执行后+1
            {
                data++;
                exit(0);
            }
            wait(NULL);
            if (pid > 0)
                printf("data is %d\n", data); // 由于vfork保证子进程先运行 所以为1
            break;
        default:
            break;
        }
    }

    return 0;
}

在这里插入图片描述

实现一个程序启动另一个程序后自身仍然在运行,即在子进程中加载执行其他程序而父进程等待子进程结束后才结束。

#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    /*接受键盘输入命令字符*/
    char buf[88];
    fgets(buf, 88, stdin);
    pid_t pid;
    pid = fork();
    /*创建子进程*/
    if (pid < 0)
        perror("创建子进程失败");
    else if (0 == pid)
    {
        /*用exec()加载程序执行输入的命令*/
        execl("/bin/sh", "sh", "-c", buf, (char *)0);
    }
    else
    {
        /*等待子进程信息*/
        wait(NULL);
        /*继续父进程的执行*/
        printf("父进程执行成功");
    }
}

在这里插入图片描述

编写一段C语言程序使其完成:父子进程通过无名管道传递三条消息:

  • 管道文件的测试程序开始
  • 管道文件测试正在进行
  • 管道通信测试结束
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/*进程间通信(IPC机制)
  通信方式有: 管道 有名管道 消息队列 信号量  共享内存 套接字
  管道:是一种半双工的通信方式 只能在具有亲缘关系的进程间使用
  有名管道:也是半双工的通信方式,但是它允许无亲缘关系进程间的通信
*/

//实现父子进程之间相互发送消息
int main()
{
    char *parent_talk[] = {"管道文件的测试程序开始", "管道文件测试正在进行", "管道通信测试结束", NULL};
    char *child_talk[] = {"好的", "一切正常", "拜拜", NULL};
    int fd1[2];
    int fd2[2];
    int res = pipe(fd1);
    if (res == -1)
    {
        printf("create pipe error.\n");
        exit(1);
    }
    res = pipe(fd2);
    if (res == -1)
    {
        printf("create pipe erroe.\n");
        exit(1);
    }
    pid_t pid;
    pid = fork();
    if (pid == 0) //子进程
    {
        close(fd1[1]); //子进程关闭fd1的写端,关闭fd2的读端
        close(fd2[0]);
        char buf[256];
        int i;
        char *talk = child_talk[i];
        while (talk != NULL)
        {
            sleep(5);
            read(fd1[0], buf, 256);
            printf("父进程:>%s\n", buf);
            write(fd2[1], talk, strlen(talk) + 1);
            i++;
            talk = child_talk[i];
        }
        close(fd1[0]);
        close(fd2[1]);
    }
    else if (pid > 0)
    {
        close(fd1[0]); //父进程关闭fd1的读端,关闭fd2的读端
        close(fd2[1]);

        char buf[256];
        int i = 0;
        char *talk = parent_talk[i];
        while (talk != NULL)
        {
            write(fd1[1], talk, strlen(talk) + 1);
            read(fd2[0], buf, 256);
            printf("子进程:>%s\n", buf);
            i++;
            talk = parent_talk[i];
        }
        close(fd1[1]);
        close(fd2[0]);
        int status;
        wait(&status);
    }
    return 0;
}

在这里插入图片描述

利用Linux/UNIX的软中断信号,编写一段C语言程序完成:显示数字1到100,在程序运行中如果捕获到一个SIGINT信号,则转去执行一段显示当前系统时间的程序。在编程中要考虑到信号被复位的情况,使程序能够实现多次被打断却多次的恢复执行。

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
void handler(int signo)
{
    signal(SIGINT, SIG_IGN);
    time_t timep;
    time(&timep);
    printf("now the time is=%s\n", asctime(gmtime(&timep)));
    signal(SIGINT, handler);
}
int main()
{
    int i;
    signal(SIGINT, handler);
    for (i = 1; i <= 100; i++)
    {
        printf("i=%d\n", i);
        sleep(1);
    }
    printf("the program ends!\n");
    return 0;
}

在这里插入图片描述

编写一段C程序完成:父进程创建一个子进程,父进程对子进程设置一个报警信号,然后父进程等待子进程的结束,如果此时报警信号先到,就终止子进程。在程序中尽量返回子进程的退出码。

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

// https://blog.csdn.net/awawfwfw/article/details/46519251

void killchild(int pid_child);

void killchild(int pid_child)
{

    printf("killing  child process   \n");
    //调用wait函数
    int pidxx;
    pidxx = wait(NULL);
    printf("killed the child process, whose pid is %d \n", pidxx);
    exit(0);
}

void killyourself(int ownid);
void killyourself(int ownid)
{

    // printf("killing  child process %d  \n",pid_child);
    printf("parent sent signal, child process killed itself  \n");
    exit(0);
}

int main()
{

    // 要捕捉的信号
    (void)signal(SIGALRM, killchild);

    int pid_child = 0;

    int pid = fork();

    if (pid == -1)
    {
        perror("fork failed\n");
        // exit(1);
        exit(EXIT_FAILURE);
    }
    if (pid == 0)
    {
        //子进程
        pid_child = getpid();
        //子进程也signal一个信号
        (void)signal(SIGHUP, killyourself);
        sleep(15);
        kill(getppid(), SIGALRM);
    }
    else
    {
        //父进程
        //等待
        // pause();
        sleep(6);
        kill(pid_child, SIGHUP);
        exit(0);
    }
}

编写一个C语言程序使其完成:两个程序testl和test2通过一个共享内存进行通信,其中testl向共享内存中写数据,test2从共享内存中读出数据或信息并将数据或信息送入标准输出上。

test1

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

struct shared_msg
{
    int update;        //更新数据标志,1:更新,0:未更新
    char text[BUFSIZ]; //记录写入和读取的文本
};
void main()
{
    printf("程序开始\n");
    key_t key;              //共享内存键值
    int shmid;              //共享内存标识
    char buf[BUFSIZ];       //输入缓冲
    struct shared_msg *msg; //共享内存地址

    //得到键值
    key = (key_t)1234;

    //创建共享内存
    shmid = shmget(key, sizeof(struct shared_msg), IPC_CREAT | 0666);
    if (shmid < 0)
    {
        //输出到错误缓冲区
        fprintf(stderr, "创建共享内存失败\n");
        exit(EXIT_FAILURE);
    }

    //将共享内存段映射到调用进程的数据段中
    msg = (struct shared_msg *)shmat(shmid, NULL, 0);
    if (msg < (struct shared_msg *)0)
    {
        fprintf(stderr, "共享内存段映射到进程失败n");
        exit(EXIT_FAILURE);
    }
    printf("共享内存地址 %X\n", (int*)msg);

    //向共享内存中写入数据
    while (1)
    {

        //向共享内存中写入数据
        printf("请输入消息:");
        //从缓冲区输入
        fgets(buf, BUFSIZ, stdin);
        strncpy(msg->text, buf, BUFSIZ);
        msg->update = 1; // 1表示数据更新,客户端要同步更新
        printf("更新数据完成\n");

        //写入数据
        if (strncmp(buf, "EOF", 3) == 0)
        {
            break;
        }
    }

    //将共享内存和当前进程分离
    if (shmdt(msg) < 0)
    {
        fprintf(stderr, "将共享内存和当前进程分离失败\n");
        exit(EXIT_FAILURE);
    }

    printf("程序结束\n");
    exit(EXIT_SUCCESS);
}

tes2

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

struct shared_msg
{
    int update;        //更新数据标志,1:更新,0:未更新
    char text[BUFSIZ]; //记录写入和读取的文本
};
void main()
{
    printf("程序开始\n");
    key_t key;              //共享内存键值
    int shmid;              //共享内存标识
    struct shared_msg *msg; //共享内存地址
    char buf[BUFSIZ];       //读取缓冲

    //得到键值
    key = (key_t)1234;

    //创建共享内存
    shmid = shmget(key, sizeof(struct shared_msg), IPC_CREAT | 0666);
    if (shmid < 0)
    {
        //输出到错误缓冲区
        fprintf(stderr, "创建共享内存失败\n");
        exit(EXIT_FAILURE);
    }

    //将共享内存段映射到调用进程的数据段中
    msg = (struct shared_msg *)shmat(shmid, NULL, 0);
    if (msg < (struct shared_msg *)0)
    {
        fprintf(stderr, "共享内存段映射到进程失败n");
        exit(EXIT_FAILURE);
    }
    printf("共享内存地址 %X\n", (int*)msg);

    //向共享内存中写入数据
    while (1)
    {
        //服务端更新数据则读取
        while (msg->update == 1)
        {
            sprintf(buf, "%s", msg->text);
            printf("读取数据:%s", buf);
            //读取完成后,将更新标志改变
            msg->update = 0;
        }
        if (strncmp(buf, "EOF", 3) == 0)
        {
            break;
        }
    }

    //将共享内存和当前进程分离
    if (shmdt(msg) < 0)
    {
        fprintf(stderr, "将共享内存和当前进程分离失败\n");
        exit(EXIT_FAILURE);
    }

    //删除共享内存
    if (shmctl(shmid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "删除共享内存失败\n");
        exit(EXIT_FAILURE);
    }

    printf("程序结束\n");
    exit(EXIT_SUCCESS);
}

在这里插入图片描述

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

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

相关文章

看5G时代,“一键喊话”的大喇叭如何奏响基层治理最强音

“喂喂&#xff0c;各位居民朋友快下楼做核酸啦……” 通过广播传递最新政策、应急预警、疫情防控等信息&#xff0c;利用智能信息播报系统&#xff0c;打通基层宣讲“最后一公里”&#xff0c;已成为全国多地的常见景象。“多亏了它&#xff0c;需要紧急通知的时候&#xff0c…

Vue--》超详细教程——vue-cli脚手架的搭建与使用

目录 vue-cli vue-cli 的安装 (可能出现的问题及其解决方法) vue-cli 创建 Vue 项目 Vue项目中目录的构成 Vue项目的运行流程 Vue组件的使用 vue-cli vue-cli是Vue.js开发的标准工具。它简化了程序员基于webpack创建工程化的Vue项目的工程。其好处就是简省了程序员花费时…

Nacos——配置中心源码详解

Nacos——配置中心源码详解配置中心客户端主动获取客户端服务端客户端长轮询更新客户端1.入口2.配置文件分片处理3.配置文件处理4.本地配置文件与缓存数据的对比5.开启长轮询与服务端对比6.通知监听器7.监听回调处理服务端1.入口2.长轮询机制3.长轮询的延迟任务4.数据变更事件总…

【U8+】用友U8同一个账套使用了好多年,需要将以前年度进行分离、删除。

【问题需求】 用友U8一个账套使用了好多年了&#xff0c; 需要将以前年度进行删除&#xff0c; 但是在系统管理中&#xff0c;查看该账套只有一个年度账&#xff08;账套库&#xff09;。 例如&#xff1a; 图中002账套&#xff0c;是从2020年开始使用至2024年&#xff0c; 现在…

SpringBoot集成Spring Security——【认证流程】

一、认证流程 上图是 Spring Security 认证流程的一部分&#xff0c;下面的讲解以上图为依据。 &#xff08;1&#xff09; 用户发起表单登录请求后&#xff0c;首先进入 UsernamePasswordAuthenticationFilter&#xff1a; 在 UsernamePasswordAuthenticationFilter中根据用户…

第十四届蓝桥杯模拟赛第一期试题【Java解析】

目录 A 二进制位数 问题描述 答案提交 参考答案 解析 B 晨跑 问题描述 答案提交 参考答案 解析 C 调和级数 问题描述 答案提交 参考答案 解析 D 山谷 问题描述 答案提交 参考答案 解析 E 最小矩阵 问题描述 答案提交 答案 解析 F 核酸日期 问题描述…

香港和新加坡,谁是亚洲加密金融中心?

去新加坡&#xff0c;还是去中国香港? 对中国Web3的创业者来说&#xff0c;是一个问题。 2022年11月&#xff0c;中国香港金融科技周和新加坡金融科技周同时举办&#xff0c;将这场竞赛推向高潮。 抢人、抢钱、抢公司……中国香港和新加坡对于“加密金融中心”或者“全球We…

2、云原生微服务实践-服务开发框架设计和实践

目录 一、依赖管理 二、服务模块管理 api、svc 三、其他文件管理 1、私密配置文件 2、前端页面单页文件 四、单体仓库 mono-repo 1、单体仓库和多仓库的对比&#xff1a; 2、单体仓库优点 五、接口参数校验 六、统一异常处理 七、DTO(数据传输对象)和DMO(数据模型对…

尝试改善科研V2

参考链接&#xff1a; https://fulequn.github.io/2022/09/26/Article202209261/ https://www.xljsci.com/ https://apps.ankiweb.net/ https://www.explainpaper.com/ 1 从动机上促成科研 将科研这件事情分成准备工作、活动本身、活动的结果。 1.1 准备工作 准备工作十分简…

湖南郴州王瑞平、大衣哥、谷传民、孟文豪唱响《知心世界》主题曲

在大衣哥和谷传民对簿公堂之时&#xff0c;来自湖南郴州的王瑞平&#xff0c;准备在他们之间架起一座沟通的桥梁。众所周知&#xff0c;大衣哥和谷传民的官司&#xff0c;是因为《火火的情怀》版权&#xff0c;其实这首歌的版权&#xff0c;并不是只属于谷传民一人。 著名音乐人…

第一个springBoot maven 项目

1. env: java 11 IntelliJ IDEA 2021.3.2 (Community Edition) 2. file->new project->Maven: pom.xml 需要导入的包&#xff1a;后面三个是jdk8升级到11后&#xff0c;可能会出错&#xff0c;需要用到的包 <parent><groupId>org.springframework.boot<…

python面向对象之类和对象相关知识

python面向对象之类和对象相关知识 一、面向对象简介 1、什么是面向对象 面向对象是一种编程思想&#xff0c;把数据和对数据的多个操作方法封装在一起组成类&#xff0c;这样通过这个类创建出来的对象,就可以直接调用这些方法了。2、面向对象相关的术语 类&#xff1a;用来…

一次金融APP的解密历程

声明&#xff1a;本文仅限于技术讨论与分享&#xff0c;严禁用于非法途径。若读者因此作出任何危害网络安全行为后果自负&#xff0c;与本号及原作者无关。 前言&#xff1a; 客户仅提供官网下载地址给我们测试。但是由于官网的版本不是最新的&#xff0c;APP会强制你升级。而…

搭建lamp平台

apache安装步骤 检查是否已经rpm安装httpd服务&#xff0c;已安装则卸载服务。 [rootlocalhost ~]# rpm -e rpm -qa | grep httpd --nodeps 开发工具安装 如果编译安装无法执行&#xff0c;可能是开发工具没有安装&#xff0c;执行下面命令即可安装。&#xff08;如已安装则跳…

【springboot进阶】优雅使用 MapStruct 进行类复制

项目中经常会遇到这样的一个情况&#xff1a;从数据库读取到数据&#xff0c;并不是直接返回给前端做展示的&#xff0c;还需要字段的加工&#xff0c;例如记录的时间戳是不需要的、一些敏感数据更是不能等等。传统的做法就是创建一个新的类&#xff0c;然后写一堆的get/set方法…

数据结构【队列】

文章目录&#xff08;一&#xff09;队列定义&#xff08;二&#xff09;队列实现&#xff08;1&#xff09;创建结构体&#xff08;2&#xff09;具体函数实现及解析1.1 初始化队列1.2入队列1.3出队列1.4取队首元素1.5取队尾元素1.6返回队列个数1.7判断是否为空1.8销毁队列&am…

springCloud的 consul的下载与安装

下载地址&#xff1a;Install | Consul | HashiCorp Developer 下载自己需要使用的版本 下载后会有一个exe 文件通过cmd 命令行来执行这个exe 文件consul agent -dev -client0.0.0.0 出现此页面后执行8500 端口 请求地址&#xff1a;http://127.0.0.1:8500/ 出现此页面说明启…

黑苹果入门:必备工具篇

以下给大家汇总的这些软件工具都是我们在安装使用黑苹果过程中可能会用到的&#xff0c;至于使用方法&#xff0c;在这里我就不做过多介绍了。 本次只提供软件下载地址&#xff0c;不提供使用方法&#xff0c;不知道如何使用软件工具的童鞋&#xff0c;可以在百度翻翻相关教程…

第5章 C语言高级的库函数

文章目录文档配套视频讲解链接地址第05章 C库函数5.1 assert.h 断言库5.2 ctype.h 测试和映射字符5.3 math.h 数学库5.4 stdlib.h 标准库1. 字符串转整数、浮点数2. strtod 把字符串中的数字转换成浮点数并返回数字的下一个字符的位置3. strtol 字符串转整数4. strtoul 字符串转…

vue3 antd多级动态菜单(二)后台管理系统(两种方法过滤有无子菜单children)

vue3 antd 多级动态菜单&#xff08;精修版本&#xff09; 两种方法实现对children的筛选相关文章推送&#xff08;供参考&#xff09;场景复现实现效果解决方法hasChildren与noChilren函数过滤v-if v-else判断有无children【推荐】&#x1f525;两种方法公用代码sunmmary下期预…