共享内存

/***************************************************************************************************************************
    该程序编译好后,需要运行两次(都保持不退出),第一次运行相当于进程1,第二次运行相当于进程2,
    进程1向共享内存写数据,进程2从共享内存读数据。输入quit则进程全部退出,并删除共享内存
***************************************************************************************************************************/

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

#define N 1024

void handler(int signo){};

int main()
{
    key_t key;
    int shmid;
    pid_t peerid;
    char *shmaddr;
    struct shmid_ds buf;
    signal(SIGUSR1, handler);  //注册SIGUSR1信号。如果不注册该信号,那么一旦接收到该信号,进程就会被杀死。handler函数什么也不做,因此该信号的功能只是唤醒该进程。

    if ((key = ftok("/", 10)) == -1)  //根据文件的inode节点来生成key。为了使进程能根据相同的文件inode节点来得到相同的key,
    {                                  //最好选择那些稳定的文件名(或目录名)来生成key,本例中使用了根目录的inode来生成key
        perror("ftok");
        return -1;
    }
    if ((shmid = shmget(key, N, 0666 | IPC_CREAT | IPC_EXCL)) == -1) //获取共享内存的id号
    {
        if (errno == EEXIST)  //如果共享内存存在,那么就打开共享内存
        {
            printf("second....");
            shmid = shmget(key, N, 0666);
            
            if ((shmaddr= (char*)shmat(shmid, NULL, 0))== (char*)-1)  //将共享内存映射到用户空间,并把首地址传给shmaddr
            {
                perror("shmat second");
                return -1;
            }

            peerid = atoi(shmaddr);  //获取第一个进程的ID
            sprintf(shmaddr, "%d", getpid()); //将自己的ID写入共享内存
            kill(peerid, SIGUSR1);  //唤醒第一个进程
            while (1)
            {
                pause();
                if (strncmp(shmaddr, "quit", 4) == 0)
                    break;
                fputs(shmaddr, stdout); //从共享内存读数据
                kill(peerid, SIGUSR1);  //读完数据后唤醒进程1
            }
        }
        else { perror("shmget second"); return -1;}
    }
    else
    {
            printf("first....");
            
            if ((shmaddr = (char*)shmat(shmid, NULL, 0)) == (char*)-1) //创建共享内存
            {
                perror("shmat first");
                return -1;
            }
            sprintf(shmaddr, "%d", getpid()); //将自己的ID写入共享内存,以便进程2读取
            pause();
            peerid = atoi(shmaddr); //获取进程2的ID
            while (1)
            {
                if (fgets(shmaddr, N, stdin) == NULL) //向共享内存写数据
                {
                    perror("fgets");
                    return -1;
                }
                if (strncmp(shmaddr, "quit", 4) == 0)
                {
                    kill(peerid, SIGUSR1);
                    break;
                }
                kill(peerid, SIGUSR1); //写完数据后唤醒进程2
                pause();
            }
    }
    if (shmdt(shmaddr) == -1) //取消共享内存映射
    {
        perror("shmdt");
        return -1;
    }    
    if (shmctl(shmid, IPC_STAT, &buf) == -1) //获取共享内存的状态信息,保存在buf里
    {
        perror("shmctl");
        return -1;
    }    
    if (buf.shm_nattch == 0)
    {
        if (shmctl(shmid, IPC_RMID, NULL) == -1)
        {
            if(errno != EINVAL) //如果报错的原因是共享内存已经被删除,则什么也不做。如果是其他原因,则打印错误信息
            {
                perror("chmctl rm ");
                return -1;
            }
            exit(-1);
        };
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值