热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux进程间通信(systemv信号灯+systemv共享内存)实例

nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd

系统V共享内存原理

进程间需要共享的数据被放在一个叫做IPC共享内存区域的地方,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。系统V共享内存通过shmget获得或创建一个IPC共享内存区域,并返回相应的标识符。内核在保证shmget获得或创建一个共享内存区,初始化该共享内存区相应的shmid_kernel结构注同时,还将在特殊文件系统shm中,创建并打开一个同名文件,并在内存中建立起该文件的相应dentry及inode结构,新打开的文件不属于任何一个进程(任何进程都可以访问该共享内存区)。

信号灯与其他进程间通信方式不大相同,

它主要提供对进程间共享资源访问控制机制。相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程同步。信号灯有以下两种类型:

二值信号灯:最简单的信号灯形式,信号灯的值只能取0或1,类似于互斥锁。
注:二值信号灯能够实现互斥锁的功能,但两者的关注内容不同。信号灯强调共享资源,只要共享资源可用,其他进程同样可以修改信号灯的值;互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。

计算信号灯:信号灯的值可以取任意非负值(当然受内核本身的约束)。

/*

 *
 *       Filename:  producer.c
 *
 *    Description:  生产者进程
 *
 *        Version:  1.0
 *        Created:  09/30/2011 04:52:23 PM
 *       Revision:  none
 *       Compiler:  gcc(g++)
 *
 *         Author:  |Zhenghe Zhang|, |zhenghe.zhang@gmail.com|
 *        Company:  |Shenzhen XXX Technology Co., Ltd.|
 *
 */

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define MAXSHM      5  //定义缓冲区数组的下标变量个数

union semun {
int val; /* value for SETVAL */
struct semid_ds *buf;/* buffer for IPC_STAT & IPC_SET */
unsigned short *array;/* array for GETALL & SETALL */
struct seminfo *__buf;/* buffer for IPC_INFO */
void *__pad;
};

int main()
{
    key_t ipckey;
    key_t semkey;

    int shmid;
    char *addr_c;

    /* 定义信号灯集,该信号灯集包含3个信号量 fullid, emptyid, mutexid  */
    int semid;

    ipckey = ftok("/home/zhang/shmipcx", 10001);
    if(ipckey == -1)
    {
        perror("ftok");
        exit(1);
    }
 
    shmid = shmget(ipckey, 1024, IPC_CREAT | 0666);
    if(shmid == -1)
    {
        perror("shmget");
        exit(1);
    }

    addr_c = (char*)shmat(shmid, NULL, 0);
    if(*((int*)addr_c) == -1)
    {
        perror("shmat");
        exit(1);
    }

    /* 定义信号量数据结构 */
    struct sembuf  P,V;
    union semun arg1, arg2, arg3;

    semkey = ftok("/home/zhang/shmipcy", 10001);
    if(semkey == -1)
    {
        perror("ftok");
        exit(1);
    }

    /* 创建信号灯集  */
    semid  = semget(semkey, 3, IPC_CREAT | 0666); //如果创建新集合(一般在服务器进程中), 则必须指定nsems
    if(semid <0)
    {
        perror("semget semid");
        exit(1);
    }

    /*初始化信号灯集中的信号量 */
    arg1.val = 0;            //初始时缓冲区中无数据 (fullid, 缓冲区满信号量)
    if(semctl(semid, 0, SETVAL, arg1) == -1)
    {
        perror("semctl setval error");
        exit(1);
    }

    arg2.val = MAXSHM;       //初始时缓冲区中有5个空闲的数组元素 (emptyid, 缓冲区空信号量)
    if(semctl(semid, 1, SETVAL, arg2) == -1)
    {
        perror("semctl setval error");
        exit(1);
    }

    arg3.val = 1;            //初始时互斥信号为1,允许一个进程进入 (mutexid, 互斥信号量)
    if(semctl(semid, 2, SETVAL, arg3) == -1)
    {
        perror("semctl setval error");
        exit(1);
    }

    /* 初始化 P, V操作  */
    P.sem_num = 0;
    P.sem_op = -1;
    P.sem_flg = SEM_UNDO;
    V.sem_num = 0;
    V.sem_op = 1;
    V.sem_flg = SEM_UNDO;
 
    int i = 0;
    while(i <10)
    {
        P.sem_num = 1;                //设置操作信号量emptyid
        semop(semid, &P, 1);         //对 emptyid执行P操作

        P.sem_num = 2;                //设置操作信号量mutexid
        semop(semid, &P, 1);         //对 mutexid执行 P操作

        addr_c[i] = i + 'a';
        printf("***addr_c[%d] = %c\n", i, addr_c[i]);

        V.sem_num = 2;                //设置操作信号量mutexid
        semop(semid, &V, 1);         //对mutexid执行 V 操作

        V.sem_num = 0;                //设置操作信号量fullid
        semop(semid, &V, 1);         //对fullid执行 V 操作

        i++;
        sleep(1);  
    }

    sleep(60); //等待消费者进程退出

    if(shmdt(addr_c) == -1)
    {
        perror("shmdt");
        exit(1);

    }

 


    /* 删除共享内存区 */

    if(shmctl(shmid, IPC_RMID, NULL) == -1)

    {

        perror("shmctl");

        exit(1);

    }


    /*   撤消信号集  */
    if(semctl(semid, 0, IPC_RMID, 0) == -1) //第三个参数cmd为IPC_RMID时,整个信号集被删除,第二个参数semnum被忽略。
    {
        perror("semctl");
        exit(1);
    }

    return 0;

}

 


/*
 *
 *       Filename:  consumer.c
 *
 *    Description:  消费者进程
 *
 *        Version:  1.0
 *        Created:  09/30/2011 04:52:23 PM
 *       Revision:  none
 *       Compiler:  gcc(g++)
 *
 *         Author:  |Zhenghe Zhang|, |zhenghe.zhang@gmail.com|
 *        Company:  |Shenzhen XXX Technology Co., Ltd.|
 *
 */

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define MAXSHM      5  //定义缓冲区数组的下标变量个数

union semun {
int val; /* value for SETVAL */
struct semid_ds *buf;/* buffer for IPC_STAT & IPC_SET */
unsigned short *array;/* array for GETALL & SETALL */
struct seminfo *__buf;/* buffer for IPC_INFO */   //test!!
void *__pad;
};

int main()
{
    key_t ipckey;
    key_t semkey;

    int shmid;
    char *addr_c;

    /* 定义信号灯集,该信号灯集包含3个信号量 fullid, emptyid, mutexid  */
    int semid;

    ipckey = ftok("/home/zhang/shmipcx", 10001);
    if(ipckey == -1)
    {
        perror("ftok");
        exit(1);
    }

    shmid = shmget(ipckey, 1024, IPC_EXCL | 0666);
    if(shmid == -1)
    {
        perror("shmget");
        exit(1);
    }
 
    addr_c = (char*)shmat(shmid, NULL, 0);
    if(*((int*)addr_c) == -1)
    {
        perror("shmat");
        exit(1);
    }

    /* 定义信号量数据结构 */
    struct sembuf  P, V;
    //union semun arg1, arg2, arg3;

    semkey = ftok("/home/zhang/shmipcy", 10001);
    if(semkey == -1)
    {
        perror("ftok");
        exit(1);
    }

    /* 创建信号灯集  */
    semid  = semget(semkey, 0, IPC_EXCL | 0666); //如果引用一个现存的集合(一个客户进程), 则将nsems指定为0
    if(semid <0)
    {
        perror("semget semid");
        exit(1);
    }

    /* 初始化 P  V操作  */
    P.sem_num = 0;
    P.sem_op = -1;  //方式是减1(解锁)
    P.sem_flg = SEM_UNDO;
    V.sem_num = 0;
    V.sem_op = 1;  //方式是加1(解锁)
    V.sem_flg = SEM_UNDO;

    int i = 0;
    while(i <10)
    {
        P.sem_num = 0;
        semop(semid,  &P, 1);       //对fullid执行 P 操作

        P.sem_num = 2;
        semop(semid, &P, 1);        //对mutexid执行 P 操作

        printf("***addr_c[%d] = %c\n", i, addr_c[i]);

        V.sem_num = 2;
        semop(semid, &V, 1);        //对mutexid执行 V 操作

        V.sem_num = 1;
        semop(semid, &V, 1);        //对empty执行 V 操作

        i++;
        sleep(2);
    }

    if(shmdt(addr_c) == -1)
    {
        perror("shmdt");
        exit(1);
    }

    return 0;
}


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
author-avatar
KNN
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有