IPC(shm+sem)

共享内存是两个或多个进程共享同一块内存区域,并通过该内存区域实现数据交换的进程间通信。虽然共享内存是进程间通信的最快速的机制,但是进程间的同步问题靠自身难以解决,于是就需要信号量机制,信号量能很好的解决互斥资源的同步问题。这些牵涉到操作系统里的知识,要好好研究一番同步互斥问题才能继续。

共享内存的工作模式一般是:

1.     int shmget(key_t key, int size, int shmflg);

创建或取得一块共享内存

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

将shmid所指共享内存和当前进程连接(attach)

3.     要做的事。。。。

4.     int shmdt(const void *shmaddr);

将先前用shmat连接好的共享内存分离(detach)当前的进程

5.     int shmctl(int shmid ,int cmd, struct shmid_ds *buf)

把cmd设成IPC_RMID删除共享内存及其数据结构

附加说明:

1.     在经过fork()后,子进程将继承已连接的共享内存地址

2.     在经过exec()后,已连接的共享内存地址会自动detach

3.     在结束进程后,已连接的共享内存地址会自动detach

信号量大致是如此的:

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

创建或获取信号队列

2. int semctl(int semid, int semnum, int cmd, union semun arg);

控制信号队列,如cmd=SETVAL设置信号量的值; 或者cmd=IPC_STAT获得          semid_ds结构

3. int semop(int semid, struct sembuf *sop, unsigned nsops);

信号处理

4. 完后将semctl的cmd设置为IPC_RMID将信号队列删除

/*一个例子程序,来自《linux环境下C编程指南》,有小改动:

*简单的服务器和客户端程序,启动不带参数运行服务器,带参数则是客户端

*服务器启动后,创建信号量和共享内存,并将共享内存的引用ID显示出来,

* 将信号量的引用ID放在共享内存中,利用服务器端提供的共享内存引用ID

*将共享内存附加到地址段,读取信号量以实现两个进程之间的同步,之后,这两个进程就可 *利用共享内存进行进程间通信,客户端输入的信息将在服务器端显示出来

*/

#include
<sys/sem.h>

#include
<sys/shm.h>

#include
<sys/ipc.h>

#include
<stdio.h>

#include
<string.h>

#include
<signal.h>

#include
<stdlib.h>

#define SHMDATASZ 1000

#define BUFSZ
(SHMDATASZ-sizeof(int))

#define SN_EMPTY 0

#define SN_FULL 1

int delete_semid = 0;

union semun

{

int val;

struct semid_ds
*buf;

ushort array;

};

void server(void);

void client(int shmid);

void delete(void);

void sigdelete(int signum);

void locksem(int semid,
int semnum);

void unlocksem(int semid,
int semnum);

void clientwrite(int shmid,
int semid,
char *buffer);

int main(int argc,
char *argv[])

{

if(argc
< 2)

server();

else

client(atoi(argv[1]));

return 0;

}

void server(void)

{

union semun sunion;

int semid, shmid;

void *shmdata;

char *buffer;

//创建2个信号量

semid = semget(IPC_PRIVATE, 2, SHM_R|SHM_W);

if(semid
== -1)

perror("semget");

delete_semid = semid;

// 当接收到SIGINT信号时删除信号量并终止程序

atexit(&delete);

signal(SIGINT,
&sigdelete);

//设EN_EMPYT的信号值为1

sunion.val = 1;

if(semctl(semid, SN_EMPTY, SETVAL, sunion)
==
-1)

perror("semctl");

sunion.val = 0;

//设EN_FULL的信号值为0,说明没有一个资源可用

if(semctl(semid, SN_FULL, SETVAL, sunion)
==
-1)

perror("semctl");

//创建一块共享内存

shmid = shmget(IPC_PRIVATE, SHMDATASZ, IPC_CREAT|SHM_R|SHM_W);

if(shmid
== -1)

perror("shmget");

//附加到shmdata

shmdata = shmat(shmid, 0, 0);

if(shmdata
==
(void*)-1)

perror("shmat");

//删除共享内存,刚刚创建还没用呢,就删了,不明白

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

// perror("shmctl");

//把信号标识符放在首地址

*(int*)shmdata
= semid;

buffer = shmdata
+ sizeof(int);  //后面是缓冲区

printf("Server is running with SHM id ** %d **\n", shmid);

while(1)

{

printf("waiting until full...");

fflush(stdout);

//申请一个资源

locksem(semid, SN_FULL);

printf("done\n");

printf("message received :%s\n", buffer);

//释放用完的资源

unlocksem(semid, SN_EMPTY);

}

}

void client(int shmid)

{

int semid;

void *shmdata;

char *buffer;

//把server创建的共享内存附加到shmdata

shmdata = shmat(shmid, 0, 0);

//取出信号标识符

semid = *(int*)shmdata;

//再找到缓冲区

buffer = shmdata+sizeof(int);

printf("client operational: shm id is %d, sem id is %d\n", shmid, semid);

while(1)

{

char input[3];

printf("\n\nMenu\n1.Send a message\n");

printf("2.Exit\n");

fgets(input,
sizeof(input),
stdin);

switch(input[0])

{

case ‘1‘:clientwrite(shmid, semid, buffer);

break;

case ‘2‘:exit(0);

break;

}

}

}

void clientwrite(int shmid,
int semid,
char *buffer)

{

printf("waiting until empty..");

fflush(stdout);

//申请EMPTY资源

locksem(semid, SN_EMPTY);

printf("Enter Message:");

fgets(buffer, BUFSZ,
stdin);

//释放资源

unlocksem(semid, SN_FULL);

}

void delete()

{

printf("\nMaster exiting; deleting semaphore %d\n", delete_semid);

if(semctl(delete_semid, IPC_RMID, 0)
==
-1)

perror("release semaphore");

}

void sigdelete(int num)

{

exit(0);

}

void locksem(int semid,
int semnum)

{

struct sembuf sb;

sb.sem_num = semnum;

sb.sem_op =
-1;

sb.sem_flg = SEM_UNDO;

semop(semid,
&sb, 1);

}

void unlocksem(int semid,
int semnum)

{

struct sembuf sb;

sb.sem_num = semnum;

sb.sem_op = 1;

sb.sem_flg = SEM_UNDO;

semop(semid,
&sb, 1);

}

参考资料《linux环境下C编程指南》《Linux C函数库参考手册》

IPC(shm+sem)

时间: 2024-08-26 03:00:35

IPC(shm+sem)的相关文章

IPC之sem.c源码解读

// SPDX-License-Identifier: GPL-2.0 /* * linux/ipc/sem.c * Copyright (C) 1992 Krishna Balasubramanian * Copyright (C) 1995 Eric Schenk, Bruno Haible * * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <[email protected]> * * SMP-threaded, sy

IPC之shm.c源码解读

// SPDX-License-Identifier: GPL-2.0 /* * linux/ipc/shm.c * Copyright (C) 1992, 1993 Krishna Balasubramanian * Many improvements/fixes by Bruno Haible. * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994. * Fixed the shm swap deallocati

《Unix网络编程》卷2 读书笔记 第2章- Posix IPC

1. 概述 Posix IPC 包括:Posix消息队列.Posix信号量.Posix共享内存区 Posix IPC在访问它们的函数和描述它们的信息上有一些类似点. 本章讲述所有这些共同属性:用于标识的路径名.打开或创建时指定的标志.访问权限. Posix IPC 函数汇总 2. IPC名字 三种类型的Posix IPC都使用“Posix IPC名字”进行标识.mq_open.sem_open.shm_open这三个函数的第一个参数就是这样的一个名字. 对于Linux,Posix IPC名字必须

C扩展 从共享内存shm到memcache外部内存

引言 - ipc - shm 共享内存 本文会通过案例了解ipc 的共享内存机制使用, 后面会讲解C 如何使用外部内存服务memcached. 好先开始了解 linux 共享内存机制. 推荐先参看下面内容回顾一下 共享内存 linux api. linux进程间的通信(C): 共享内存    http://blog.chinaunix.net/uid-26000296-id-3421346.html 上面文章可以简单看一下概念.  下面这篇文章好些, 可以细看加深共享内存api使用熟练度. Li

+++++++进程管理工具 top/htop/glances/dstat命令

pstree,ps,pgrep,pkill,pidof top,htop glance,pmap, vmstat,dstat kill job,bg,fg,nohup sar,tsar,iosar,iftop 注释: [string] 后台的内核线程 1.线程内共享进程内存,共享打开文件描述符(文件内容) 2.线程是进程的子单位 3.调度.跟踪困难 USER  PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND USER:

Linux互斥与同步应用(四):posix信号量的互斥与同步

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 在前面讲共享内存的IPC时曾说共享内存本身不具备同步机制,如果要实现同步需要使用信号量等手段来实现之,现在我们就来说说使用posix的信号量来实现posix多进程共享内存的同步.其实信号量也可以使用在同一进程的不同线程之间. 信号量是一个包含非负整数的变量,有两个原子操作,wait和post,也可以说是P操作和V操作,P操作将信号量减一,V操作

Linux系统性能监控工具

Linux 系统性能监控 1 htop [[email protected] ~]# htop   1  [||                                       2.1%]     Tasks: 51, 73 thr; 1 running   2  [|                                        0.3%]     Load average: 0.00 0.02 0.00    Mem[|||||||||||||||||||||||

linux系统调用表(system call table)

系统调用号 函数名 入口点 源码 0 read sys_read fs/read_write.c 1 write sys_write fs/read_write.c 2 open sys_open fs/open.c 3 close sys_close fs/open.c 4 stat sys_newstat fs/stat.c 5 fstat sys_newfstat fs/stat.c 6 lstat sys_newlstat fs/stat.c 7 poll sys_poll fs/sel

Linux中信号量处理

参考文章: http://blog.csdn.net/qinxiongxu/article/details/7830537/ 信号量一. 什么是信号量信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程( 线程)所拥有.信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0, 说明它被占用,测试的线程要进入睡眠队列中, 等待被唤醒.二. 信号量的分类在学习信号量之前,我们必须先知道—— Linux提供两种信号量:(1) 内核信号量,由内核控制路径使用(2) 用户态进