1.基础知识:
(1)共享内存是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间的数据传递不再涉及内核,即进程不再通过执行进入内核的系统调用来传递彼此的数据。
(2)共享内存的生命周期随内核。
(3)注意:共享内存未提供任何保护资源,即共享内存自身没有同步与互斥机制,但它是临界资源,所以我们需要利用其它机制来保证数据的正确性,Linux下就可以用信号量达到同步的目的。
(4)linux共享内存有两种方式(本文主要介绍shmget方式):
1)mmap方式,适用于父子进程之间,创建的内存非常大时;
2)shmget方式,适用于同一台电脑上不同进程之间,创建的内存相对较小。
(5)进程间利用共享内存实现消息队列的基本原理如下图
2.相关函数
1.semget
1.函数原型
2.函数功能
创建或者获取一个已经存在的信号量;
如果为全新创建,也就是不知道是否有人创建过,则IPC_CREATE|IPC_EXCEL,就是如果没
有则创建
,
如果有则创建失败
;
3.参数
key:两个进程使用相同的key值,就可以使用同一个信号量;
nsems:创建几个信号量;
semflg:标志位;如果为创建:IPC_CREAT;
4.返回值
成功返回一个非负整数即该信号集的标识码;失败返回-1
2.semop
1.函数原型
2.函数功能
对信号量进行改变,做P操作或者V操作;
3.参数
semid:信号量的id号,也就是刚才semget的返回值;说明对哪个信号量进行操作;
sops:结构体指针,指向sembuf的结构体指针,sembuf结构体有三个成员变量:sem_num表
示信号量的编号
(
即指定信号量集中的信号量下标
);
nsops:表示是p还是v操作;1为v操作 (加1),-1为p操作(减1);sem_flg为标志位;
4.返回值
成功返回0;失败返回-1
5.说明
unsigned short sem_num; /* semaphore number */第几个信号量
short sem_op; /* semaphore operation */p(-1)操作还是v操作(+1)
short sem_flg; /* operation flags */标志位
3.semctl
1.函数原型
**注意**:联合体semun,这个联合体需要自己定义;
2.函数功能
控制信号量集 对信号量进行控制:初始化/删除信号量
3.参数
semid:信号量id; 由semget函数返回的信号量集标识码
semnum:信号量编号; 信号量集中信号量的序号
cmd:命令:SETVAL:初始化信号量; IPC_RMID:删除信号量; 将要采取的动作(有三个可取值)
4.返回值
成功返回0,失败返回-1
3.思路:
4.代码
1. sem.h
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>
union semun
{
int val;
};
void sem_init();
void sem_p(int index);
void sem_v(int index);
void sem_destroy();
2.sem.c
#include "sem.h"
#define SEM_NUM 2
static int semid = -1;
void sem_init()
{
semid = semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);//全新创建
if (semid == -1 )
{
semid = semget((key_t)1234,SEM_NUM,0600);
if ( semid == -1)
{
printf("semget err\n");
return;
}
}
else
{
int arr[SEM_NUM] = {1,0};
for( int i = 0; i < SEM_NUM; i++ )
{
union semun a;
a.val = arr[i];
if ( semctl(semid,i,SETVAL,a) == -1 )//全新创建成功,就初始化
{
printf("semctl err\n");
}
}
}
}
void sem_p(int index)
{
if ( index < 0 || index >= SEM_NUM )
{
return;
}
struct sembuf buf;
buf.sem_num = index;
buf.sem_op = -1;//p
buf.sem_flg = SEM_UNDO;
if ( semop(semid,&buf,1) == -1 )
{
printf("sem p err\n");
}
}
void sem_v(int index)
{
if ( index < 0 || index >= SEM_NUM )
{
return;
}
struct sembuf buf;
buf.sem_num = index;
buf.sem_op = 1;//v
buf.sem_flg = SEM_UNDO;
if ( semop(semid,&buf,1) == -1 )
{
printf("sem v err\n");
}
}
void sem_destroy()
{
if ( semctl(semid,0,IPC_RMID) == -1 )
{
printf("semctl del err\n");
}
}
3.a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include "sem.h"
int main()
{
int shmid = shmget((key_t)1234,256,0600|IPC_CREAT);//创建/获取共享内存
if ( shmid == -1 )
{
printf("shmget err\n");
exit(0);
}
char* s = (char*)shmat(shmid,NULL,0);
if ( s == (char*)-1 )
{
printf("shmat err\n");
exit(0);
}
sem_init();//2 1,0
while( 1 )
{
printf("input\n");
char buff[128] = {0};
fgets(buff,128,stdin);
sem_p(0);
strcpy(s,buff);
sem_v(1);
if ( strncmp(buff,"end",3) == 0 )
{
break;
}
}
shmdt(s);
exit(0);
}
4.b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include "sem.h"
int main()
{
int shmid = shmget((key_t)1234,256,0600|IPC_CREAT);//创建/获取共享内存
if ( shmid == -1 )
{
printf("shmget err\n");
exit(0);
}
char* s = (char*)shmat(shmid,NULL,0);
if ( s == (char*)-1 )
{
printf("shmat err\n");
exit(0);
}
sem_init();//2 1,0
while( 1 )
{
printf("input\n");
char buff[128] = {0};
fgets(buff,128,stdin);
sem_p(0);
strcpy(s,buff);
sem_v(1);
if ( strncmp(buff,"end",3) == 0 )
{
break;
}
}
shmdt(s);
exit(0);
}
只运行b.c,会阻塞