IPC:system V 信号量和共享内存

2023-05-16

信号量相关知识

结构体

 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
							   (Linux-specific) */
};
struct semid_ds {
   struct ipc_perm sem_perm;  /* Ownership and permissions */
   time_t          sem_otime; /* Last semop time */
   time_t          sem_ctime; /* Last change time */
   unsigned long   sem_nsems; /* No. of semaphores in set */
};
struct ipc_perm {
   key_t          __key; /* Key supplied to semget(2) */
   uid_t          uid;   /* Effective UID of owner */
   gid_t          gid;   /* Effective GID of owner */
   uid_t          cuid;  /* Effective UID of creator */
   gid_t          cgid;  /* Effective GID of creator */
   unsigned short mode;  /* Permissions */
   unsigned short __seq; /* Sequence number */
};
struct  seminfo {
	int semmap;  /* Number of entries in semaphore
				 map; unused within kernel */
	int semmni;  /* Maximum number of semaphore sets */
	int semmns;  /* Maximum number of semaphores in all
				 semaphore sets */
	int semmnu;  /* System-wide maximum number of undo
				 structures; unused within kernel */
	int semmsl;  /* Maximum number of semaphores in a
				 set */
	int semopm;  /* Maximum number of operations for
				 semop(2) */
	int semume;  /* Maximum number of undo entries per
				 process; unused within kernel */
	int semusz;  /* Size of struct sem_undo */
	int semvmx;  /* Maximum semaphore value */
	int semaem;  /* Max. value that can be recorded for
				 semaphore adjustment (SEM_UNDO) */
};

semget 

semget()函数用于创建一个新的信号量集合,或者访问现有的集合。其原型如下,其中第1个参数key是ftok生成的键值,第2个参数nsems参数可以指定在新的集合中应该创建的信号量的数目,第3个参数semflsg是打开信号量的方式。

semflsg是打开信号量的方式。

IPC_CREAT:如果内核中不存在这样的信号量集合,则把它创建出来。

IPC_EXCL:当与IPC_CREAT一起使用时,如果信号量集合早已存在,则操作将失败。

        如果单独使用IPC_CREAT,semget()或者返回新创建的信号量集合的信号量集合标识符;或者返回早已存在的具有同一个关键字值的集合的标识符。如果同时使用IPC_EXCL和IPC_CREAT,那么将有两种可能的结果:如果集合不存在,则创建一个新的集合;如果集合早已存在,则调用失败,并返回-1。IPC_EXCL本身是没有什么用处的,但当与IPC_CREAT组合使用时,它可以用于防止为了访问而打开现有的信号量集合。 

 semget - get a System V semaphore set identifier

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

       int semget(key_t key, int nsems, int semflg);

semop 

信号量的P、V操作是通过向已经建立好的信号量(使用semget()函数),发送命令来完成的。向信号量发送命令的函数是semop(),这个函数的原型如下: 

NAME
       semop, semtimedop - System V semaphore operations

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

       int semop(int semid, struct sembuf *sops, size_t nsops);

       int semtimedop(int semid, struct sembuf *sops, size_t nsops,
                      const struct timespec *timeout);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       semtimedop(): _GNU_SOURCE

semop()函数第2个参数(sops)是一个指针,指向将要在信号量集合上执行操作的一个数组,而第3个参数(nsops)则是该数组中操作的个数。sops参数指向的是类型为sembuf结构的一个数组。sembuf结构是在linux/sem.h中定义的,如下所示。 

struct sembuf{
    ushort sem_num;
    short sem_op;
    short sem_flag; 
};

sem_num:用户要处理的信号量的编号。

sem_op:将要执行的操作(正、负,或者零)。

sem_flg:信号量操作的标志。如果sem_op为负,则从信号量中减掉一个值。如果sem_op为正,则从信号量中加上值。如果sem_op为0,则将进程设置为睡眠状态,直到信号量的值为0为止。 

例如“struct sembuf sem={0,+1,NOWAIT};”表示对信号量0,进行加1的操作。用函数semop()可以构建基本的P、V操作,代码如下所示。Sem_P构建{0,+1,NOWAIT}的sembuf结构来进行增加1个信号量值的操作;Sem_V构建{0,-1,NOWAIT}的sembuf结构来进行减少1个信号量的操作,所对应的信号量由函数传入(semid)。

semctl

NAME
       semctl - System V semaphore control operations

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

       int semctl(int semid, int semnum, int cmd, ...);

测试一:测试信号量的创建、加、减、取值、设置值操作

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

#define DEBUG_INFO(format, ...) printf("%s:%d -- " format "\n", __func__, __LINE__,##__VA_ARGS__)

typedef int sem_t;
union semun
{
	int 			val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *__buf;
};


int sem_p(sem_t semid){
    struct sembuf sops = {0,+1,IPC_NOWAIT};
    return semop(semid,&sops,1);
}
int sem_v(sem_t semid){
    //struct sembuf sops = {0,+1,IPC_NOWAIT};
    struct sembuf sops = {0,-1,IPC_NOWAIT};
    return semop(semid,&sops,1);
}
void set_sem_value(sem_t semid, int value){
    union semun sem;
    sem.val = value;
    semctl(semid,0,SETVAL,sem);
}
void get_sem_value(sem_t semid, int *value){
    union semun sem;
    *value = semctl(semid,0,GETVAL,sem);
}
void delete_sem(sem_t semid){
    union semun sem;
    sem.val;
    semctl(semid,0,IPC_RMID,sem);
}
sem_t create_sem(key_t key,int value){
    union semun sem;
    sem_t semid;
    sem.val = value;
    semid = semget(key,1,IPC_CREAT|0666);
    if(semid == -1){
        perror("semget");
        exit(-1);
    }
    semctl(semid,0,SETVAL,sem);
    return semid;
}

int main(int argc, char **argv){

    key_t key;
    int semid;
    int value = 0;
    key = ftok("/home/lkmao",'a');
    if(key == -1){
        perror("ftok");
        exit(-1);
    }
    DEBUG_INFO("key = %d",key);

    DEBUG_INFO("system V sem");
    semid = create_sem(key,0);
    get_sem_value(semid,&value);
    DEBUG_INFO("value = %d",value);

    sem_p(semid);
    get_sem_value(semid,&value);
    DEBUG_INFO("value = %d",value);

    sem_v(semid);
    get_sem_value(semid,&value);
    DEBUG_INFO("value = %d",value);

    set_sem_value(semid,5);
    get_sem_value(semid,&value);
    DEBUG_INFO("value = %d",value);

    delete_sem(semid);
    return 0;
}

测试结果:

main:65 -- key = 1627463214
main:67 -- system V sem
main:70 -- value = 0
main:74 -- value = 1
main:78 -- value = 0
main:82 -- value = 5

这肯定不是我们期待的用法,我们期待的是,让它实现进程间的通信,点解?

测试二:信号量实现进程间的通信

共享内存相关知识

 shmget函数 

NAME
       shmget - allocates a System V shared memory segment

SYNOPSIS
       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmget(key_t key, size_t size, int shmflg);

shmat函数 

NAME
       shmat, shmdt - System V shared memory operations

SYNOPSIS
       #include <sys/types.h>
       #include <sys/shm.h>

       void *shmat(int shmid, const void *shmaddr, int shmflg);

       int shmdt(const void *shmaddr);

shmdt用于删除共享内存

shmctl 函数


NAME
       shmctl - System V shared memory control

SYNOPSIS
       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmctl(int shmid, int cmd, struct shmid_ds *buf);
struct shmid_ds {
   struct ipc_perm shm_perm;    /* Ownership and permissions */
   size_t          shm_segsz;   /* Size of segment (bytes) */
   time_t          shm_atime;   /* Last attach time */
   time_t          shm_dtime;   /* Last detach time */
   time_t          shm_ctime;   /* Last change time */
   pid_t           shm_cpid;    /* PID of creator */
   pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
   shmatt_t        shm_nattch;  /* No. of current attaches */
   ...
};
struct ipc_perm {
   key_t          __key;    /* Key supplied to shmget(2) */
   uid_t          uid;      /* Effective UID of owner */
   gid_t          gid;      /* Effective GID of owner */
   uid_t          cuid;     /* Effective UID of creator */
   gid_t          cgid;     /* Effective GID of creator */
   unsigned short mode;     /* Permissions + SHM_DEST and
							   SHM_LOCKED flags */
   unsigned short __seq;    /* Sequence number */
};

测试二:

子进程和父进程连接到同一块共享内存。子进程修改共享内存。父进程采用阻塞模式等待信号量。

子进程休眠5秒,证明父进程确实是在阻塞,5秒后,子进程对信号量执行P操作,父进程被欢迎,读取并打印共享内存的内容。

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

#define DEBUG_INFO(format, ...) printf("%s:%d -- " format "\n", __func__, __LINE__,##__VA_ARGS__)

typedef int sem_t;
union semun
{
	int 			val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *__buf;
};


int sem_p(sem_t semid){
    struct sembuf sops = {0,+1,IPC_NOWAIT};
    return semop(semid,&sops,1);
}
int sem_v(sem_t semid){
    //struct sembuf sops = {0,+1,IPC_NOWAIT};//
    struct sembuf sops = {0,-1,0};//阻塞模式,无信号则阻塞
    return semop(semid,&sops,1);
}
void set_sem_value(sem_t semid, int value){
    union semun sem;
    sem.val = value;
    semctl(semid,0,SETVAL,sem);
}
void get_sem_value(sem_t semid, int *value){
    union semun sem;
    *value = semctl(semid,0,GETVAL,sem);
}
void delete_sem(sem_t semid){
    union semun sem;
    sem.val;
    semctl(semid,0,IPC_RMID,sem);
}
sem_t create_sem(key_t key,int value){
    union semun sem;
    sem_t semid;
    sem.val = value;
    semid = semget(key,1,IPC_CREAT|0666);
    if(semid == -1){
        perror("semget");
        exit(-1);
    }
    semctl(semid,0,SETVAL,sem);
    return semid;
}

static char msg[] = "hello moka moka\n";

int main(int argc, char **argv){

    key_t key;
    int semid,shmid;
    int value = 0;
    pid_t pid;
    key = ftok("/home/lkmao",'a');
    if(key == -1){
        perror("ftok");
        exit(-1);
    }
    DEBUG_INFO("key = %d",key);
    //创建共享内存
    shmid = shmget(key,1024,IPC_CREAT|0666);
    if(shmid == -1){
        perror("shmget");
        exit(-1);
    }
    //创建信号量
    semid = create_sem(key,0);
    pid = fork();
    if(pid == -1){
        perror("fork");
        exit(-1);
    }
    if(pid == 0){
        DEBUG_INFO("child %u",getpid());
        char *shm = (char*)shmat(shmid,0,0);
        memcpy(shm,msg,sizeof(msg));
        sleep(5);
        sem_p(semid);
        shmdt(shm);
    }
    if(pid > 0){
        DEBUG_INFO("parent:%u",getppid());
        char *shm = (char*)shmat(shmid,0,0);
        memcpy(shm,msg,sizeof(msg));
        sem_v(semid);
        DEBUG_INFO("shm = %s",shm);
        shmdt(shm);
    }
    //delete_sem(semid);
    return 0;
}

执行结果:

main:70 -- key = 1627463214
main:93 -- parent:68538
main:85 -- child 68637
main:97 -- shm = hello moka moka

小结

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IPC:system V 信号量和共享内存 的相关文章

  • 通过 mmap 文件进行 IPC:应该使用原子和/或易失性吗?

    我使用 mmap 文件在进程之间共享数据 代码是这样的 struct Shared int Data int file open file dat O RDWR Shared shared static cast
  • 如何用C++读取系统信息?

    我正在尝试使用 C 获取 Linux 系统上的操作系统版本 硬盘空间 可用磁盘空间以及已安装 RAM 等信息 我知道我可以使用system 运行不同的 Linux 命令并捕获它们的输出 这就是我目前正在做的 但我想知道是否有更好的方法 C
  • 使用数据库(MySql)的生产者/消费者系统,这可行吗?

    我需要使用某物协调我的系统与多个消费者 生产者 每个消费者 生产者在具有不同操作系统的不同机器上运行 我一直在研究使用 MySql 来做到这一点 但这似乎非常困难 我的要求很简单 我希望能够随时添加或删除消费者 生产者 因此他们根本不应该相
  • 如果系统命令/反引号中的脚本失败,则主脚本需要退出状态!=0

    Code of inter pl is use strict use warnings my var1 cat gra def ment ckfile txt ckfile txt doesn t exist print Hello Wor
  • Delphi:系统菜单打开了吗?

    在 Delphi 中 我需要一个函数来确定系统菜单 分别是窗口菜 单 单击图标时出现的菜单 是否打开 原因是我正在编写一个反键盘记录器功能 它将垃圾发送到当前活动的编辑控件 这也阻止了键盘记录器读取 WinAPI 消息来读取内容 但是 如果
  • 如何在 OS X C 代码中创建异步计时器?

    所以这个问题实际上是 为什么 time h 在 OS X 和 Linux 上不一样 但是 我已经接受了这些分歧 为了在 Unix 系统上创建计时器 我遵循了本教程http www helsinki fi atk unix dec manua
  • 如何设置系统范围的umask?

    我在一个运行 Linux Debian 和 Ubuntu 的实验室工作 用户名和组名由 NIS 和 yp 处理 我们有一些公共用户 每个人都可以访问来运行实验 然后我们每个人都有自己的用户 此外还有一个我们都是其中成员的公共组 我怎样才能使
  • 将参数发送到驻留在另一个进程中的应用程序实例

    我有一个单实例应用程序 c WPF net3 51 检查应用程序是否已实例化是通过互斥体完成的 如果应用程序已在运行 我会从已打开的应用程序实例中打开一个新窗口 到目前为止效果很好 但是 由于应用程序扩展 我现在必须将 e Args 或至少
  • 如何打开给定文件的用户系统首选编辑器?

    我试图弄清楚如何打开给定文件的系统首选编辑器 假设我们有一个用 Java 编写的文件管理器 用户转到文件夹并查看文件列表 并且 例如 有一个文件Icon jpg 用户双击文件名 文件将在系统的首选编辑器 即 Gimp 中打开 主要问题是 如
  • Windows服务之间如何通信

    我有 2 个使用 C 创建的 Windows 服务 我希望其中一个服务调用第二个 Windows 服务中的函数 我该怎么做呢 EDIT 问题是我必须运行该应用程序 我不需要它们 相反服务进程也很好 但我need这2个应用程序进行通信 这2个
  • iOS 应用程序可以通过套接字进行通信吗?

    我将为 iOS 开发一些应用程序 他们可以通过套接字相互通信吗 假设一个应用程序作为服务器运行 即使在后台模式下 另一个应用程序作为客户端连接到服务器应用程序并执行一些通信 它是否违反了任何 App Store 规则 如果我的想法由于某种原
  • 使用AppService的连接持续时间有限制吗?

    我有一个 UWP 应用程序托管应用服务 https learn microsoft com en us windows uwp launch resume how to create and consume an app service在同
  • Java 和 C/C++ 之间进程间通信的最快(低延迟)方法

    我有一个Java应用程序 通过TCP套接字连接到用C C 开发的 服务器 应用程序和服务器都在同一台机器 Solaris 机器 上运行 但我们最终正在考虑迁移到 Linux 交换的数据类型是简单消息 登录 登录ACK 然后客户端请求某些内容
  • 获取进程段的开始和结束 C/C++

    我需要获取以下进程段的开始和结束地址 代码 数据 堆栈 环境 我了解它如何位于内存中 但不知道如何使用 api 调用或其他方式获取它 我找到了如何使用此代码开始某些片段 include
  • Linux 消息队列 - 多个接收者

    我最近一直在研究和研究 Linux 消息队列 并遇到了一些我不太明白为什么会发生的事情 如果我们运行两个程序 它们都在无限 for 循环中使用 msgrcv 来检查消息 然后发送两条消息 那么第一个运行的程序将收到第一条消息 第二个程序将收
  • 无法在 Linux 中阻止从命名管道 (FIFO) 读取

    很奇怪 我似乎无法完成这项工作 这是我的架构 我有一个命名管道 它将在永远运行 root读取器进程和多个应用程序编写器进程 读者进程必须是blocking当作家们在nonblocking 因此 这就是我在阅读器进程中所做的 该进程将运行ro
  • 在 C# 中进行进程间通信 (IPC) 最简单的方法是什么? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我有两个 C 应用程序 我希望其中一个向另一个发送两个整数 这不必很快 因为它每隔几秒调用一次 做到这一点最简单的方法是什么 它不一定是最优雅的
  • 如何用Java写入OS系统日志?

    Mac OS 有一个名为 Console 的应用程序 其中包含记录的消息 错误和故障 我相信 Windows 中的等效项是事件查看器 我想 Linux 上也有一个 但我不知道它是什么 也不知道它在哪里 是否可以像这样从 Java 输出获取消
  • 无法获取 android.permission.CLEAR_APP_USER_DATA

    我正在开发需要特殊权限的系统应用程序 由于某种原因 我无法获得 CLEAR APP USER DATA 权限 但我可以使用 INSTALL PACKAGES DELETE PACKAGES 等 什么可能导致这种情况 显现 uses perm
  • 如何在同一设备上运行的 Android 应用程序之间传输文件?

    我正在编写一个与 RESTful 服务交互的 Android 应用程序 该 Web 服务本质上是一个文件系统 并提供元数据以及对文件的 CRUD 访问 我的应用程序检索元数据 并通过ContentProvider 我需要添加与我的应用程序在

随机推荐

  • python实现的文本编辑器

    wxpython实现的文本编辑器 效果如下 xff1a 主要功能 xff1a 1 编辑保存文本 xff0c 打开修改文本 2 常用快捷键 xff0c 复制 xff0c 粘贴 xff0c 全选等 3 支持撤销功能 4 支持弹出式菜单 代码如下
  • C语言开发Linux下web服务器(支持GET/POST,SSL,目录显示等)

    这个主要是在CSAPP基础上做的 xff0c 添加了POST xff0c SSL xff0c 目录显示等功能 一 实现功能 xff1a 1 支持GET POST方法 2 支持SSL安全连接即HTTPS 3 支持CGI 4 基于IP地址和掩码
  • sklearn2pmml xgboost缺失值(missing)处理的坑

    sklearn2pmml xgboost缺失值 missing 处理的坑 今天同事在部署xgboost pmml模型时遇到了大坑 xff0c 线上spark预测和本地python预测结果怎么都不对应 xff0c 记录一下处理过程 看了下同事
  • adb导出手机应用到电脑

    简单说一下相关步骤 xff0c 以备不时之需 1 手机开启usb调试 2 Windows系统 Win 43 R打开命令行窗口 xff0c 输入adb devices xff0c 如果连接成功会出现机子的序列号 3 adb shell pm
  • Js作用域与作用域链详解

    一直对Js的作用域有点迷糊 xff0c 今天偶然读到Javascript权威指南 xff0c 立马被吸引住了 xff0c 写的真不错 我看的是第六版本 xff0c 相当的厚 xff0c 大概1000多页 xff0c Js博大精深 xff0c
  • windows10环境下tensorflow安装教程

    楼主最近一直忙着找工作 最近几个月一直all in java 好久没学机器学习 深度学习 前几天突然通知要提交论文中期了 于是赶紧打开电脑 结果发现之前安装的tensorflow居然登陆不上了 折腾了半天 搜过各种csdn博客 一直安装失败
  • 'gbk' codec can't encode character '\xa0'

    从网上抓了一些字节流 xff0c 想打印出来结果发生了一下错误 xff1a UnicodeEncodeError 39 gbk 39 codec can 39 t encode character 39 xbb 39 in position
  • 【Git记录学习】github创建项目以及本地使用(vscode)

    一 github创建空仓库 从github中创建空仓库 在执行完上一步操作后会返回这样的界面 xff0c 包括了一些基本的git操作以及HttpS SSH地址 生成一个readme md文档 xff08 步骤2 Set up下面有蓝色的超链
  • 关于DFT变换含义、公式和具体形式

    原文地址 xff1a http blog sina com cn s blog 7853c3910102v9wd html 这篇文章从实际工程应用的角度 xff0c 记录一下如何计算 xff0c 关于公式 变形和应用 维基百科上的 DFT公
  • 1602显示数字不稳定一直跳动(AD转换)

    程序如下所示 首先说明下 xff0c 此程序为AD转换芯片PCF8591采集电压数据 xff0c 然后送到1602显示 现象 xff1a 1602显示的数字一直频繁的跳动 xff0c 乱花眼 此现象不是一直出现的 xff0c 有时候会出现
  • C++11中的线程类

    前面介绍的线程是利用了POSIX线程库 xff0c 这是传统C C 43 43 程序员使用线程的方式 xff0c 而C 43 43 11提供了语言层面使用线程的方式 C 43 43 11新标准中引入了5个头文件来支持多线程编程 xff0c
  • 4.4.1内核编译

    内核源码下载地址 xff1a https mirrors edge kernel org pub linux kernel v4 x linux 4 4 1 tar gz 安装依赖包 xff1a 报错就装 cp boot config xx
  • fatal error: hugetlbfs.h: No such file or directory

    fatal error hugetlbfs h No such file or directory 解决办法 xff1a sudo apt get update sudo apt get install libhugetlbfs dev
  • WSL下 配置NFS-失败

    配置一个IP地址 xff1a sudo ip addr add 192 168 250 2 24 broadcast 192 168 250 255 dev eth2 sudo apt get install nfs kernel serv
  • OMT 对象模型、动态模型和功能模型

    对象模型描述系统中对象的静态结构 对象之间的关系 对象的属性 对象的操作 对象模型表示静态的 结构上的 系统的 数据 34 特征 对象模型为动态模型和功能模型提供了基本的框架 xff0c 对象模型用包含对象和类的对象图来表示 OMT的对象模
  • 关于epoll的调试的几个问题

    将今天调试的几个小问题点总结下 xff0c 后续遇到再添加 一 将总结的问题点放在最前面 1 epoll wait的maxevents参数 epoll wait的maxevents参数 xff0c 经过测试 xff0c maxevents的
  • poll函数测试

    一 基础知识 include lt poll h gt int poll struct pollfd fds nfds t nfds int timeout 其中参数fds指向一个结构体数组的第0个元素的指针 xff0c 每个数组元素都是一
  • IPC:匿名管道和命名管道

    一 管道初级测试 写两个小程序 xff0c 一个负责向管道发数据 xff0c 一个从管道接收数据 xff1b pipe cpp include lt iostream gt using namespace std int main cout
  • IPC:system V消息队列

    ftok函数 ftok convert a pathname and a project identifier to a System V IPC key SYNOPSIS include lt sys types h gt include
  • IPC:system V 信号量和共享内存

    信号量相关知识 结构体 union semun int val Value for SETVAL struct semid ds buf Buffer for IPC STAT IPC SET unsigned short array Ar