Linux Linux程序练习十五(进程间的通信共享内存版)

/*
 * 题目:
 * 编写程序,要去实现如下功能:
 父进程创建子进程1和子进程2、子进程1向子进程2发送可靠信号,并传送额外数据为子进程1的pid*2;
 子进程2接受可靠信号的值,并发送给父进程,父进程把接受的值进行打印。
 提示:用sigqueue和sigaction实现
 * */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/shm.h>

/* 分析:
 * 子进程2将pid存入共享内存区,子进程1从共享内存区中读取子进程2的pid,向子进程2发送带数据的信号
 * */

//子进程2信号安装回调函数
void handler(int sign, siginfo_t * info, void *p)
{
    if (sign == SIGRTMIN)
    {
        printf("子进程2接收到数据%d\n",info->si_value.sival_int);
        //向父进程发送信号
        if (sigqueue(getppid(), SIGRTMIN, info->si_value) != 0)
        {
            perror("sigqueue() err");
            return;
        }
        //退出子进程2
        printf("子进程2 quit\n");
        exit(0);

    }
}

//父进程信号安装回调函数
void handlerf(int sign, siginfo_t * info, void *p)
{
    if (sign == SIGRTMIN)
    {
        //打印信号值
        printf("父进程接收的值是%d\n", info->si_value.sival_int);
    }
}

int main(int arg, char *args[])
{
    //创建共享内存区
    int shmid = shmget(IPC_PRIVATE, sizeof(int), 0666);
    if (shmid == -1)
    {
        printf("shmget() failed !\n");
        return -1;
    }
    pid_t pid = 0;
    pid = fork();
    if (pid == -1)
    {
        perror("fork() err");
        return -1;
    }
    if (pid == 0)
    {
        //子进程1
        printf("子进程1的pid=%d\n", getpid());
        int *pid2 = NULL;
        //子进程1附加到共享内存区
        pid2 = (int *) shmat(shmid, 0, 0);
        if ((int) pid2 == -1)
        {
            perror("shmat() err");
            return -1;
        }
        //等待进程2向共享内存区写入数据
        while (*pid2 == 0)
        {
            //等待共享内存区中有数据
            sleep(1);
        }
        //向进程2发送可靠信号
        union sigval v1;
        v1.sival_int = getpid() * 2;
        if (sigqueue(*pid2, SIGRTMIN, v1) != 0)
        {
            perror("sigqueue() err");
            return -1;
        }
        //发送完信号后,进程1退出
        printf("子进程1 exit\n");
        exit(0);
    }
    pid = fork();
    if (pid == -1)
    {
        perror("fork() err");
        return -1;
    }
    if (pid == 0)
    {
        //子进程2
        printf("子进程2的pid=%d\n", getpid());
        //安装信号SIGRTMIN
        struct sigaction act;
        act.sa_sigaction = handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_SIGINFO;
        if (sigaction(SIGRTMIN, &act, NULL) != 0)
        {
            printf("sigaction() failed !\n");
            return -1;
        }
        int *mypid = NULL;
        //子进程2附加到共享内存区
        mypid = (int *) shmat(shmid, 0, 0);
        if ((int) mypid == -1)
        {
            perror("shmat() err");
            return -1;
        }
        //将子进程2的pid放到共享内存区,操作私有共享内存区,映射到系统共享内存区
        *mypid = getpid();
        //等待子进程1向自己发送信号
        while (1)
        {
            printf("子进程2 sleep\n");
            sleep(1);
        }
    }
    //父进程
    //安装信号SIGRTMIN
    struct sigaction act;
    act.sa_sigaction = handlerf;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    if (sigaction(SIGRTMIN, &act, NULL) != 0)
    {
        printf("sigaction() failed !\n");
        return -1;
    }
    int ret=0;
    //等待子进程
    while(1)
    {
        ret=wait(NULL);
        printf("子进程pid=%d\n",ret);
        if(ret==-1)
        {
            if(errno==EINTR)
            {
                continue;
            }
            break;
        }
    }
    //释放共享内存区
    if (shmctl(shmid, IPC_RMID, NULL) != 0)
    {
        printf("shmctl() failed!\n");
    }
    printf("game is over !\n");
    return 0;
}

/*
 * 出错总结:gdb报错:shmat() err: Invalid argument,意思是shmat()参数不正确
 * 经过半天分析,发现我在父进程中没有wait子进程,直接调用了shmctl()函数,把共享内存给释放了,所以报错
 * */

时间: 2024-12-13 09:26:21

Linux Linux程序练习十五(进程间的通信共享内存版)的相关文章

linux_c开发(5-4)进程间通讯_共享内存通讯

共享内存 共享内存 是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快方法,一个进程向共享内存写入了数据,共享这个内存的所有进程就可以立刻看到其中内容. 共享内存实现分为两个步骤 1.创建共享内存,使用shmget函数. 2.映射共享内存,将创建的这段共享内存映射到具体的进程空间去,使用shmat函数. int shmget(key_t key,int size,int shmflg) key标志共享内存的键值:O/IPC_PRIVATE.当key的取值为IPC/PRIVATE

控制台程序使用SendMessage进行进程间的通信

消息发送者代码 本实例中创建窗体类ProxyForm,负责发送和接收数据. Main方法代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleSender { class Program { static void Main(string[] args) { ProxyForm proxy = new ProxyForm(); Consol

Linux进程间的通信

一.管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: A. 管道是半双工的,数据只能向一个方向流动: B. 需要双工通信时,需要建立起两个管道: C. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程): D. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中. 匿名管道的创建:该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义;因此,一

linux 进程间的通信

现在linux使用的进程间通信方式:(1)管道(pipe)和有名管道(FIFO)(2)信号(signal)(3)消息队列(4)共享内存(5)信号量(6)套接字(socket) 为何进行进程间的通信:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.资源共享

Linux/UNIX进程间的通信(1)

进程间的通信(1) 进程间的通信IPC(InterProcessCommunication )主要有以下不同形式: 半双工管道和FIFO:全双工管道和命名全双工管道:消息队列,信号量和共享存储:套接字和STREAMS 管道 pipe函数 当从一个进程连接到另一个进程时,我们使用术语管道.我们通常是把一个进程的输出通过管道连接到另一个进程的输入. 管道是由调用pipe函数创建的: #include<unistd.h> int pipe(intpipefd[2]); 经由参数pipefd返回两个文

Linux System Programming 学习笔记(五) 进程管理

1. 进程是unix系统中两个最重要的基础抽象之一(另一个是文件) A process is a running program A thread is the unit of activity inside of a process the virtualization of memory is associated with the process, the threads all share the same memory address space 2. pid The idle pro

Linux/UNIX之进程间的通信(2)

进程间的通信(2) 有三种IPC我们称为XSI IPC,即消息队列.信号量以及共享存储器,它们之间有很多相似之处. 标识符和键 每个内核的IPC结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符加以引用.例如,为了对一个消息队列发送或取消息,只需要知道其队列标识符.与文件描述符不同,IPC标识符不是小的整数.当一个IPC结构被创建,以后被删除时,与这种结果相关的标识符连续加1,知道达到一个整型数的最大值,然后又回到0. 标识符是IPC对象的内部名.为使多个合作进程能够在同一IPC对象上

Linux进程间的通信方法

linux进程间的通信方法总结如下 通过fork函数把打开文件的描述符传递给子进程 通过wait得到子进程的终结信息 通过加锁的方式,实现几个进行共享读写某个文件 进行间通过信号通信,SIGUSR1和SIGUSR2实现用户定义功能 利用pipe进行通信 FIFO文件进行通信 mmap,几个进程映射到同一内存区 SYS IPC 消息队列,信号量(很少用) UNIX Domain Socket,常用

嵌入式Linux裸机开发(十五)——LCD

嵌入式Linux裸机开发(十五)--LCD 一.LCD简介 LCD(Liquid Crystal Display)是液晶显示器简称.LCD的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的. 1.LCD类型 按照背光源的不同,LCD可以分为CCFL和LED两种. A.CCFL 指用CCFL(冷阴极荧光灯管)作为背光光源的液晶显示器(L