一起talk C栗子吧(第九十五回:C语言实例--使用共享内存进行进程间通信一)



各位看官们,大家好,上一回中咱们说的是SystemV IPC结构概述的例子,这一回咱们说的例子是:使用共享内存进行进程间通信。闲话休提,言归正转。让我们一起talk C栗子吧!

共享内存是SystemV IPC结构这种抽象概念的一种具体对象。就和它的名字一样,它提供了一段内存空间供不同的进程使用,进程之间可以通过该内存空间传递数据,进而实现进程间的通信。

在介绍共享内存的使用方法之前,我们先介绍几个函数,这些函数都是用来操作共享的内存的。

shmget函数

int shmget(key_t key, size_t size,int shmflag)

该函数用来获取共享内存,函数返回共享内存的标识符,我们可以通过该标识符使用共享内存;

  • 第一个参数是键值,通过它来操作IPC在内核中的结构,也就是共享内存在内核中的结构;(上一回中介绍过)
  • 第二个参数是共享内存的容量,单位是byte;
  • 第三个参数是共享内存的权限标记,该权限和文件权限一样;
  • 该函数运行成功时返回共享内存标识符,否则返回-1;

在使用该函数的时候,我们需要自己定义一个共享内存的类型,并且计算出该类型的内存空间。共享内存的类型可以依据程序需要来定义,常见的是定义一个结构体类型。

shmat函数

void * shmat(int shm_id, const void *shm_addr,int shmflg)

该函数用来把共享内存连接到进程的地址空间中,这样进程就可以使用共享内存了;

  • 第一个参数是共享内存的标识符,通过shmget函数可以获得;
  • 第二个参数是一个地址,该地址表示共享内存连接到进程中的位置;
  • 第三个参数是一个位标记,只有三个值供使用:SHM_RND,SHM_RDONLY还有0;
  • 该函数运行成功时返回指向共享内存第一个字节的指针,否则返回-1;

在使用该函数的时候,第二个参数通常使用一个空指针,空指针表示让系统自己选择共享内存连接到进程地址空间的位置,这时第三参数可以使用SHM_RDONLY或者0。如果给第二个参数指定了地址,那么第三个参数需要使用SHM_RND。

shmdt函数

int shmdt(const void *shm_addr)

该函数用来把共享内存从进程的地址空间中分离出来,分离以后进程就不能使用共享内存了;

  • 第一个参数是一个地址,它是共享内存第一个字节的指针,也就是shmat函数的返回值;
  • 该函数运行成功时返回0,否则返回-1;

shmctl函数

int shmctl(int shm_id, int cmd,struct shmid_ds *buf)

该函数用来把共享内存连接到进程的地址空间中,这样进程就可以使用共享内存了;

  • 第一个参数是共享内存的标识符,通过shmget函数可以获得;
  • 第二个参数是一个命令,表示对共享内存的操作,只有三个命令供使用:IPC_STAT,IPC_SET和IPC_RMID;
  • 第三个参数是一个结构体指针,该结构体中有共享内存的权限和所有者等信息;
  • 该函数运行成功时返回0,否则返回-1;

我们通常使用该函数删除共享内存,这时候需要给第二个参数赋值为IPC_RMID,表示删除共享内存,第三参数可以为空指针。第二个参数的另外两个命令:

  • IPC_STAT表示把第三个参数中的内容和共享内存关联起来;
  • IPC_SET表示把第三个参数中的内容设置为共享内存的值。

第三个参数的类型,我们在上一回中提起过,它和SystemV IPC的结构类似,除了必须有的成员外,它还有自己特有的成员。

我从源代码中找到了第三个参数的类型,详细的定义如下:(位于linux-4.0.3/include/linux/shm.h文件中)

struct shmid_kernel /* private to the kernel */
{
        struct kern_ipc_perm    shm_perm;
        struct file             *shm_file;
        unsigned long           shm_nattch;
        unsigned long           shm_segsz;
        time_t                  shm_atim;
        time_t                  shm_dtim;
        time_t                  shm_ctim;
        pid_t                   shm_cprid;
        pid_t                   shm_lprid;
        struct user_struct      *mlock_user;

        /* The task created the shm object.  NULL if the task is dead. */
        struct task_struct      *shm_creator;
        struct list_head        shm_clist;      /* list by creator */
};

各位看官,关于使用共享内存进行进程间通信的例子咱们就说到这里。欲知后面还有什么例子,且听下回分解 。


时间: 2024-08-05 10:54:31

一起talk C栗子吧(第九十五回:C语言实例--使用共享内存进行进程间通信一)的相关文章

一起talk C栗子吧(第九十六回:C语言实例--使用共享内存进行进程间通信二)

各位看官们.大家好,上一回中咱们说的是使用共享内存进行进程间通信的样例,这一回咱们接着上一回内容继续说使用共享内存进行进程间通信. 闲话休提,言归正转.让我们一起talk C栗子吧! 我们在上一回中介绍了共享内存的概念和相关函数的使用方法.这一回中我们通过详细的样例来说明怎样使用共享内存进行进程间的通信.以下是使用共享内存的详细步骤: 1.定义一个结构体类型,用来当作共享内存的类型: 2.使用shmget函数获取共享内存,代码中的键使用了111这个随机数字. 3.使用shmat函数把共享连接到进

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 &

一起talk C栗子吧(第十五回:C语言实例--双向链表)

各位看官们,大家好,从今天开始,我们讲大型章回体科技小说 :C栗子,也就是C语言实例.闲话休提, 言归正转.让我们一起talk C栗子吧! 看官们,上一回中咱们说的是循环链表的例子,这一回咱们说的例子是:双向链表. 看官们,双向链表也是一种链表.我们在前面两回中说到的链表,都是沿着链表头部到链表尾部这样的方 向进行操作,而今天咱们要说的双向链表既可以沿着链表头部到链表尾部这样的方向进行操作,也可以沿 着链表尾部到链表头部这样的方向进行操作.这也是正是叫它双向链表的原因. 在例子中,查找和删除结点

一起talk C栗子吧(第十二回:C语言实例--单链表一)

各位看官们,大家好,从今天开始,我们讲大型章回体科技小说 :C栗子,也就是C语言实例.闲话休提, 言归正转.让我们一起talk C栗子吧! 看官们,上一回中咱们没有说具体的例子,而且是说了例子中的文件组织结构.这一回咱们继续说C例子, 说的例子是链表,更准确的说法叫作单链表.咱们不但要说C例子,而且会在例子中使用上一回中说过的 文件组织结构,就当作是举例说明文件组织结构的使用方法. 有点一石二鸟的感觉,哈哈. 链表定义 看官们,所谓的链表其实就是一组元素通过一定的方式链接在一起.比如我们坐的火车

一起talk C栗子吧(第一百三十一回:C语言实例--C程序内存布局三)

各位看官们,大家好.上一回中咱们说的是C程序内存布局的样例,这一回咱们继续说该样例.闲话休提,言归正转.让我们一起talk C栗子吧. 看官们,关于C程序内存布局的样例,我们在前面的两个章回都介绍过了,这一回我们将对前面章回中的内容进行总结和提示. 内存布局总结 C程序的内存布局主要有四个分区:代码区,数据区(data和bss).堆区和栈区.能够使用readelf -S filename查看各个分区的内存地址.这四个分区在内存中从低地址空间開始依次向高地址延伸.我们再次使用前面章回中的图直观地展

一起talk C栗子吧(第二回:C语言实例--判断闰年)

各位看官们,大家好,从今天开始,我们讲大型章回体科技小说 :C栗子,也就是C语言实例.闲话休提, 言归正转.让我们一起talk C语言实例吧! 看官们,上一回中咱们给小说做了个开头,这一回咱们正式说C例子,这回说的例子是:判断闰年. 看官们,闰年是什么?这个是地理天文方面的概念.如果不明白的话,自己百度去,哈哈.我也偷一把懒. 看官们,判断闰年的方法有两种: 如果某年能被4整除,但是不能被100整除,那么这一年就是闰年. 如果某年能被400整除,那么这一年就是闰年. 看官们看到整除肯定想到除法了

一起talk C栗子吧(第八十五回:C语言实例--使用信号进行进程间通信二)

各位看官们,大家好,上一回中咱们说的是使用信号进行进程间通信的样例,这一回咱们接着上一回的内容,继续说该样例.闲话休提.言归正转. 让我们一起talk C栗子吧. 我们在上一回中举了使用信号进行进程间通信的样例,在该样例中.我们通过终端发出信号.当进程收到该信号后让它运行系统对信号定义的默认动作.这一回.我们再来举一个使用信号进行进程间通信的样例,只是.我们发送和处理信号的方式和上一回的样例不一样.在接下来的样例中,我们在一个进程中使用kill产生信号.在另外一个进程中接收而且依照自己的方式处理

一起talk C栗子吧(第三十五回:C语言实例--测试程序运行时间)

各位看官们,大家好,上一回中咱们说的是巧用溢出计算最值的例子,这一回咱们说的例子是:测试程序 运行时间.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,在编写程序的时候,可能需要计算程序运行的时间.通过计算时间,可以查看程序的性能.其实 我们在第三十一回中对各种常用排序算法总结时也使用过这种方法,不过当时使用的是Linux提供的time 命令.如果大家忘记了第三十一回的内容,可以点击这里查看. 我们今天说的测试程序运行时间,是让程序自己测试运行时间,而不是像第三十一回中哪样借用其它工

一起talk C栗子吧(第一百七十五回:C语言实例--获取当前终端的行数和列数)

各位看官们,大家好,上一回中咱们说的是关闭终端中缓冲功能的例子,这一回咱们说的例子是:获取当前终端的行数和列数 .闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在前面章回中介绍了termios相关的信息,以及termios提供的编程接口,通过这些接口可以操作终端,今天我们再介绍一些操作终端的编程接口,通过这些接口可以获取当前终端的行数和列数,这便是我们今天的主题. int setupterm(char *term, int fd, int *errret); 该函数用来修改当前