IPC通信:
共享内存,信号量集,消息队列
查看所有的IPC
指令:ipcs
shm共享内存 ipcs -m
sem信号量集 ipcs -s
msg消息队列 ipcs -q
删除:
ipcrm -m 标识符 删共享内存
ipcrm -s 标识符 删信号量集
ipcrm -q 标识符 删消息队列
键值:ftok
键值含义:用于标识共享内存、消息队列以及信号量集
保证多个进程打开的共享内存、消息队列、信号量集是同一个
# include <sys/types.h>
# include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
参数:pathname就是你指定的文件名(该文件必须是存在而且可以访问的)
proj_id:0-255的任意一个数
返回值:当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回
int key = ftok(“/home/fuc/2_208”,1);
共享内存
1.创建共享内存
2.将共享内存映射到自己的进程空间,得到首地址
3.操作地址对应的空间
4.不想用了,解除映射
5.彻底不用了,删除
1》创建/获取共享内存 -- shmget:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
参数
key:键值 ftok的返回值;
size:大小
shmflg:IPC_CREAT|0664
如果共享内存不存在,创建并打开,存在,只打开
返回值:成功返回内存段标识符,失败-1
2》映射:把共享内存区域映射到调用进程的地址空间中去
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid:要映射的共享内存区标识符
shmaddr:NULL
shmflg:默认 0:共享内存可读写
返回值:
成功:被映射的段地址void * -- 万能指针
失败返回NULL
3》解除映射
int shmdt(const void *shmaddr);
参数: 被映射的共享内存段地址,shmat的返回值
返回值:成功返回0失败返回-1
4》删除/修改共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数: shmid: shmget的返回值
cmd: 选择的操作
IPC_STAT:获取共享内存属性,传入空的buf
IPC_SET:修改共享内存的属性,传入设置号的buf
IPC_RMID:删除共享内存,此时第三个参数为NULL
buf:根据第二个参数决定
插入:
内存复制:memcpy
void *memcpy(void *destin, void *source, unsigned n);
参数
destin:指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
source:指向要复制的数据源,类型强制转换为 void* 指针。
n-- 要被复制的字节数。
返回值
该函数返回一个指向目标存储区destin的指针。
功能
从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。
memcpy() 并不关心被复制的数据类型,只是逐字节地进行复制
信号量集
1》创建信号量集合:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
semget:创建一个信号量集或访问一个已存在的信号量集
int semget(key_t key, int nsems, int semflg);
参数:key:键值使用ftok从文件路径名中产生
nsems:通常取值为1,表示创建1组信号量;
semflg:IPC_CREA|0666表示若信号量集合已存在,返回该信号量集合的标识符,不存在,创建并返回信号量集合的标识符
返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1
2》信号量的初始化 semctl - 控制信号量信息
int semctl(int semid, int semnum, int cmd, ...);
参数
semid:是由 semget 返回的信号量标识符。
semnum:你要初始化的信号量的编号(从0开始)
cmd 命令:
删除 IPC_RMID(立即删除信号集,唤醒所有被阻塞的进程)
获取 GETVAL(根据 semnum指定的编号返回相应信号的值, 此时该函数返回值就是你要获得的信号量的值,不再是 0或-1)
设置 SETVAL(根据 semunm 指定的编号设定相应信号的值(用联合体中val成员的值设置信号量集合中单个信号量的值))
如果有第四个参数类型如下
union semun {
short val; /*SETVAL用的值*/
struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构(则是一个内核结构体)*/
unsigned short* array; /*SETALL、GETALL用的数组值*/
struct seminfo *buf; /*为控制IPC_INFO提供的缓存(表示信号量系统资源配置信息)*/
返回值:成功:返回相应的值,失败:返回-1
3》信号量的还原和消耗semop
int semop(int semid, struct sembuf *sops, unsigned nsops);
形参:
semid:semget返回值,就是信号量集和的标识符
sops:对信号量的操作,封装了一个结构体里面有
struct sembuf{
unsigned short sem_num; //信号在信号集中的索引,0代表第一个信号,1代表第二个信号
short sem_op; //操作类型 +1,-1
sem_op > 0 信号加上 sem_op 的值 sem_op < 0 信号减去 sem_op 的值。
short sem_flg; //操作标志0,设置信号量的默认操作
}
nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作
返回值:成功时,返回 0;失败时,返回-1
举例:
struct sem P = {0,-1,0};
struct sem V = {0,+1,0};
消耗:semop(semid, &P,1);//阻塞
还原:semop(semid, &V,1);
例题:通过两个进程,利用共享内存与信号量集输出helloworld++++++++++
首先创建1.c 2.c 分别用于利用共享内存与信号量集将信息存放到映射出来的内存中,3.c用来读取打印,seminit.c用来初始化
代码如下
1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/sem.h>
int main()
{
int key = ftok("/home/fuc",66);
//创建共享内存:
int shmid = shmget(key,2000,IPC_CREAT|0644);
if(shmid == -1)
{
perror("shmget");
return -1;
}
//映射
char *p = (char *)shmat(shmid,NULL,0);
if( p == NULL )
{
perror("shmat");
return -1;
}
//获取信号量集合
int key1 = ftok("/home/fuc",666);
int semid = semget(key1,1,IPC_CREAT|0666);
if(semid == -1)
{
perror("semget");
return -1;
}
struct sembuf P = {0,-1,0};
struct sembuf V = {0,+1,0};
//操作 p
int count = 0;
while(1)
{
//消耗
semop(semid,&P,1);
strcat(p,"hello");
usleep(1000);
strcat(p,"world");
//还原
semop(semid,&V,1);
count++;
if(count == 100)
{
break;
}
}
//解除映射
shmdt(p);
}
2.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/sem.h>
int main()
{
int key = ftok("/home/fuc",66);
//创建共享内存:
int shmid = shmget(key,2000,IPC_CREAT|0644);
if(shmid == -1)
{
perror("shmget");
return -1;
}
//映射
char *p = (char *)shmat(shmid,NULL,0);
if( p == NULL )
{
perror("shmat");
return -1;
}
//获取信号量集合
int key1 = ftok("/home/fuc",666);
int semid = semget(key1,1,IPC_CREAT|0666);
if(semid == -1)
{
perror("semget");
return -1;
}
struct sembuf P = {0,-1,0};
struct sembuf V = {0,+1,0};
//操作 p
int count = 0;
while(1)
{
//消耗
semop(semid,&P,1);
strcat(p,"+++++");
usleep(1000);
strcat(p,"+++++");
semop(semid,&V,1);
//还原
count++;
if(count == 100)
{
break;
}
}
//解除映射
shmdt(p);
}
3.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
int main()
{
int key = ftok("/home/fuc",66);
//创建共享内存:
int shmid = shmget(key,2000,IPC_CREAT|0644);
if(shmid == -1)
{
perror("shmget");
return -1;
}
//映射
char *p = (char *)shmat(shmid,NULL,0);
if( p == NULL )
{
perror("shmat");
return -1;
}
//操作 p
printf("%s\n",p);
//解除映射
shmdt(p);
}
seminit.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int main()
{
int key = ftok("/home/fuc",11);
int semid = semget(key,1,IPC_CREAT|0666);
if(semid == -1)
{
perror("semget");
return -1;
}
union semun set;
set.val = 1;//表示二值信号量
int res = semctl(semid,0,SETVAL,set);
if(res == -1)
{
perror("semctl");
return -1;
}
return 0;
}
首先初始化,然后再同时运行1.c 2.c 同时运行方法./1.c & ./2.c 最后运行3.c进行打印内容