IPC进程间通信
进程间通信的几种方法:
1.信号函数sigqueue()
2.管道
3.信号
4.消息队列
5.共享内存:使多个进程能够访问同一个共享内存空间(最快的IPC形式)
6.信号量:主要作为进程间以及同一进程不同线程的同步手段
7.套接口:可用于不同机器间的进程通信
//*****************************************消息队列函数***************************************************
//2013.10.21.陈顺明
//int msgget(key_t key, int msgflg)
//作用:用来创建和访问一个消息队列
//参数:
// key: 某个消息队列的名字
// msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
// 如果操作成功,msgget将返回一个非负整数,即该消息队列的标识码
//返回:如果失败,则返回“-1”
//int msgctl(int msqid, int command, strcut msqid_ds *buf)
// 作用:消息队列的控制函数,与共享内存的控制函数很相似
// 参数:
// msqid: 由msgget函数返回的消息队列标识码; command:是将要采取的动作,(有三个可取值)IPC_RMID是删除队列
// 返回:如果操作成功,返回“0”;如果失败,则返回“-1”
// int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz,int msgflg);
// 作用:作用:把一条消息添加到消息队列里去
// 参数:
// msgid: 由msgget函数返回的消息队列标识码
// msg_ptr:是一个指针,指针指向准备发送的消息,
// msg_sz:是msg_ptr指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内(计算大小不包含int type消息类型)
// msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
// 返回:操作成功,返回“0”,如果失败,则返回“-1”
//int msgrcv(int msgid, void *msg_ptr, size_t msgsz, long int msgtype,int msgflg)
// 作用:是从一个消息队列里检索消息
// 参数:
// msgid: 由msgget函数返回的消息队列标识码
// msg_ptr:是一个指针,指针指向准备接收的消息,
// msgsz:是msg_ptr指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内
// msgtype:它可以实现接收优先级的简单形式(设置类型type,只接收该类型的;如果设置成0,表示从第一个数据开始接收)
// msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
// 返回:操作成功,返回实际放到接收缓冲区里去的字符个数,如果失败,则返回“-1”
//*****************************************消息队列函数***************************************************
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
typedef struct Messege
{
int type;
char messege[1024];
}Messege_T;
typedef struct IntMsg
{
int type;
int data;
}IntMsg_T;
int main()
{
// int msgid = msgget((key_t)1234, IPC_CREAT | 0766); //创建ipc消息队列
// int msgid = msgget((key_t)1234, 0); //打开消息队列
// printf("msgid is : %d\n", msgid);
// msgctl(msgid, IPC_RMID, NULL); //删除消息队列
//安全的创建方式::创建的时候先打开,判断是否存在消息队列,如果有,删除,最后创建
int msgid = msgget((key_t)1234, 0); //打开消息队列
if (msgid > 0)
{
msgctl(msgid, IPC_RMID, NULL); //判断是否存在要创建的消息队列,如果有,删除消息队列
}
msgid = msgget((key_t)1234, IPC_CREAT | 0766); //创建ipc消息队列
printf("msgid is : %d\n", msgid);
//把字符型内容添加到消息队列
Messege_T msg;
memset(&msg, 0, sizeof(Messege_T));
msg.type = 1;
strcpy(msg.messege, "HElloWorld\n");
msgsnd(msgid, &msg, sizeof(Messege_T)-sizeof(int), 0);
strcpy(msg.messege, "ChenShunming\n"); //再添加一条字符型内容
msgsnd(msgid, &msg, sizeof(Messege_T)-sizeof(int), 0);
//把int型内容添加到消息队列
IntMsg_T intmsg;
memset(&intmsg, 0, sizeof(IntMsg_T));
intmsg.type = 2;
intmsg.data = 100;
msgsnd(msgid, &intmsg, sizeof(IntMsg_T)-sizeof(int), 0);
//从消息队列里获取消息(消息队列的接收)
// Messege_T rcvmsg;
// memset(&rcvmsg, 0, sizeof(Messege_T));
// msgrcv(msgid, &rcvmsg, sizeof(Messege_T)-sizeof(int), 1, 0);//这里的长度不算类型长度,后一个参数1为类型type
// printf("Get messege data: %s\n", rcvmsg.messege);
//msgtype如果设置成0,表示从第一个数据开始接收
while(1)
{
Messege_T rcvmsg;
memset(&rcvmsg, 0, sizeof(Messege_T));
msgrcv(msgid, &rcvmsg, sizeof(Messege_T)-sizeof(int), 0, 0);//这里的长度不算类型长度,后一个参数1为类型type
printf("Get messege data: %s\n", rcvmsg.messege);//打印的时候int类型的数据打印不出来。
}
return 0;
}
Linux里面shell命令ipcs查看ipc信息
[root@bogon ~]# ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 98304 root 600 393216 2 dest
0x00000000 131073 root 600 393216 2 dest
0x00000000 163842 root 600 393216 2 dest
0x00000000 196611 root 600 393216 2 dest
0x00000000 229380 root 600 393216 2 dest
0x00000000 262149 root 600 393216 2 dest
0x00000000 294918 root 600 393216 2 dest
0x00000000 327687 root 600 393216 2 dest
0x00000000 360456 root 600 393216 2 dest
------ Semaphore Arrays --------
key semid owner perms nsems
0x4d004237 0 root 600 8
------ Message Queues --------
key msqid owner perms used-bytes messages
//*****************************************共享内存(系统内核的内存)***************************************************
//2013.10.21.陈顺明
//int shmget(key_t key,size_t size, int shmflg)
// 作用:用来创建共享内存
// 参数:
// key: 这个共享内存段的名字
// size: 需要共享的内存量
// shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
// 返回:如果共享内存创建成功,shmget将返回一个非负整数,即该段共享内存的标识码;如果失败,则返回“-1”
// void* shmat(int shm_id, const void *shm_addr, int shmflg)让系统内存给我们分配逻辑地址,让它指向共享内存的首地址
// 作用:共享内存段刚被创建的时候,任何进程还都不能访问它,为了建立对这个共享内存段的访问渠道,
// 必须由我们来把它连接到某个进程的地址空间,shmat函数就是用来完成这项工作的。
// 参数:
// shm_id: shmget返回的共享内存标识
// shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址
// /shmaddr为0,核心自动选择一个地址(**一般把标志设置成0**)
// /shmaddr不为0且shmflg无SHM_RND标记,则以shmaddr为连接地址。
// /shmaddr不为0且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
// shmflg=SHM_RDONLY,表示连接操作用来只读共享内存
// shmflg:是一组按位OR(或)在一起的标志。它的两个可能取值是SHM_RND和SHM_RDONLY
// 返回:调用成功,返回一个指针,指针指向共享内存的第一个字节,如果失败,则返回“-1”
// int shmctl(int shm_id, int command, struct shmid_ds *buf)
// 作用:共享内存的控制函数
// 参数:
// shm_id: 由shmget返回的共享内存标识码
// command:将要采取的动作(有三个可取值) IPC_RMID删除
// buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
// 返回:操作成功,返回0,失败则返回-1
//int shmdt(const void *shm_addr)
// 作用:把共享内存与当前进程脱离开,脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已
// 参数:shm_addr: 由shmat返回的地址指针
// 返回:操作成功,返回“0”,失败则返回“-1”
//*****************************************共享内存(系统内核的内存)***************************************************
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
int main()
{
int shmid = shmget((key_t)0001, 0, 0); //打开共享内存(后两个参数要设置成0)
if (shmid > 0)
{
shmctl(shmid, IPC_RMID, NULL); //如果存在共享内存,删除共享内存
}
shmid = shmget((key_t)0001, 1024, IPC_CREAT | 0766); //创建共享内存(要设置大小)
printf("shmid is :%d\n", shmid);
void *ptr = shmat(shmid, NULL, 0); //给共享内存关联逻辑地址
printf("ptr is: %p\n", ptr); //打印逻辑地址
memcpy(ptr, "HelloWorld!\n", strlen("HelloWorld!\n")); //给共享内存的地址拷贝内容
char acBuf[1024] = {0};
memcpy(acBuf, ptr, 1024); //从共享内存里读取数据(拷贝数据)
printf("Read Data is: %s\n", acBuf);
shmdt(ptr); //删除映射的逻辑地址
shmctl(shmid, IPC_RMID, NULL); //删除共享内存
return 0;
}
//*********************************************信号量(semaphore)**********************************************
/*2013.10.22.陈顺明*/
// int semget (key_t key,int num_sems,int sem_flag);
// 作用:创建一个新的信号量或者取得一个现有信号量的键字
// 参数:
// key: 是一个整数值,不相关的进程将通过这个值去访问同一个信号量
// num_sems:需要使用的信号量个数,它几乎总是取值为1
// sem_flags:是一组标志,其作用与open函数的各种标志很相似,它低端的九个位是该信号量的权限,其作用相当于文件的访问权限,可以与键值IPC_CREATE做按位的OR操作以创建一个新的信号量
// 返回:成功时将返回一个正数值,它就是其他信号量函数要用到的那个标识码,如果失败,将返回-1
// int semctl(int sem_id,int sem_num,int command,…)(*具体 man semctl)
// 作用:允许我们直接控制信号量的信息
// 参数:
// sem_id: 是由semget函数返回的一个信号量标识码
// sem_num: 信号量的编号,如果在工作中需要使用到成组的信号量,就要用到这个编号;(信号量的下标)
//它一般取值为0,表示这是第一个也是唯一的信号量
// comman:将要采取的操作动作
// 返回:如果还有第四个参数,那它将是一个“union semun”复合结构(最后有备注)
//*********************************************信号量(semaphore)**********************************************
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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) */
};
int sem_create(key_t key, int num_sems) //创建信号量
{
int semid = semget(key, num_sems, IPC_CREAT |0766);
if (semid < 0)
{
perror("Semaphore creat error!\n");
}
return semid;
}
int sem_open(key_t key, int num_sems) //打开信号量
{
int semid = semget(key, num_sems, 0);
if (semid < 0)
{
perror("Semaphore open error!\n");
}
return semid;
}
int sem_setval(int semid, int sem_num, int value) //设置信号量
{
union semun arg;
arg.val = value;
int ret = semctl(semid, sem_num, SETVAL, arg);
if (ret < 0)
{
perror("Semaphore set value error!\n");
}
return ret;
}
int sem_getval(int semid, int sem_num) //获取信号量
{
int ret = semctl(semid, sem_num, GETVAL);
if (ret < 0)
{
perror("Semaphore get value error!\n");
}
return ret;
}
int sem_setall(int semid, int sem_num, unsigned short *array)//设置所有信号量
{
union semun arg;
arg.array = array;
int ret = semctl(semid, sem_num, SETALL, arg);//sem_num为信号量下标从下标位置开始设置所有信号量(设置起始位置)
if (ret < 0)
{
perror("Semaphore setall value error!\n");
}
return ret;
}
int sem_getall(int semid, int sem_num, unsigned short *array) //获取所有信号量值
{
union semun arg;
arg.array = array;
int ret = semctl(semid, sem_num, GETALL, arg);
if (ret < 0)
{
perror("Semaphore setall value error!\n");
}
return ret;
}
int sem_distory(int semid) //删除信号量
{
int ret = semctl(semid, 0, IPC_RMID);
if (ret < 0)
{
perror("Semaphore delet error!\n");
}
return ret;
}
int main()
{
int semid = sem_create(ftok(".", getpid()), 5);//key_t ftok(const char *pathname, int proj_id) 根据路径名和ID生成随机的key值
sem_setval(semid, 0, 100); //设置下标为0的信号量值为100
int value = sem_getval(semid, 0); //获取下标为0的信号量的值
printf("value : %d\n", value); //打印获取到下标为0的信号量的值
unsigned short array[5];
int i = 0;
for (i = 0; i < 5; i++) //初始化一个数组
{
array[i] = i;
}
sem_setall(semid, 0, array); //从0位置开始设置所有信号量
for (i = 0; i < 5; i++) //打印所有信号量的值
{
printf("get value: %d\n", sem_getval(semid, i));
}
unsigned short newarray[5];
sem_getall(semid, 0, newarray); //获取到的所有信号量值给newarray数组
for (i = 0; i < 5; i++) //打印获取到的所有信号量的值
{
printf("get all value: %d\n", newarray[i]);
}
sem_distory(semid); //删除信号量
return 0;
}
/******************************************PV锁操作********************************************************************
//*********************************************信号量pv操作(semaphore)**********************************************
/*2013.10.22.陈顺明*/
//信号量操作封装
//PV锁让只能一个进程操作
//*********************************************信号量pv操作(semaphore)**********************************************
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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*/
};
int sem_create(key_t key, int num_sems) //创建信号量
{
int semid = semget(key, num_sems, IPC_CREAT |0766);
if (semid < 0)
{
perror("Semaphore creat error!\n");
}
return semid;
}
int sem_open(key_t key, int num_sems) //打开信号量
{
int semid = semget(key, num_sems, 0);
if (semid < 0)
{
perror("Semaphore open error!\n");
}
return semid;
}
int sem_setval(int semid, int sem_num, int value) //设置信号量
{
union semun arg;
arg.val = value;
int ret = semctl(semid, sem_num, SETVAL, arg);
if (ret < 0)
{
perror("Semaphore set value error!\n");
}
return ret;
}
int sem_getval(int semid, int sem_num) //获取信号量
{
int ret = semctl(semid, sem_num, GETVAL);
if (ret < 0)
{
perror("Semaphore get value error!\n");
}
return ret;
}
int sem_setall(int semid, int sem_num, unsigned short *array) //设置所有信号量
{
union semun arg;
arg.array = array;
int ret = semctl(semid, sem_num, SETALL, arg); //sem_num为信号量下标从下标位置开始设置所有信号量(设置起始位置)
if (ret < 0)
{
perror("Semaphore setall value error!\n");
}
return ret;
}
int sem_getall(int semid, int sem_num, unsigned short *array) //获取所有信号量值
{
union semun arg;
arg.array = array;
int ret = semctl(semid, sem_num, GETALL, arg);
if (ret < 0)
{
perror("Semaphore setall value error!\n");
}
return ret;
}
int sem_distory(int semid) //删除信号量
{
int ret = semctl(semid, 0, IPC_RMID);
if (ret < 0)
{
perror("Semaphore delet error!\n");
}
return ret;
}
int sem_p(int semid, int semnum) //信号量P操作
{
struct sembuf buf = {semnum, -1, 0};
int ret = semop(semid, &buf, 1); //最后一个参数1(struct sembuf 数组就一个,如果是buf[2],参数就是2)
if (ret < 0)
{
perror("Semaphore p operate error!\n");
}
return ret;
}
int sem_v(int semid, int semnum) //信号量V操作
{
struct sembuf buf = {semnum, 1, 0};
int ret = semop(semid, &buf, 1);
if (ret < 0)
{
perror("Semaphore V operate error!\n");
}
return ret;
}
//**********************************************PV锁让只能一个进程操作****************************************
int main()
{
int semid = sem_create((key_t)3333, 1); //创建信号量,有1组信号量
sem_setval(semid, 0, 1); //设置下标为0的信号量值为1
int pid = fork();
if (pid > 0)
{
while(1)
{
sem_p(semid, 0); //执行P操作,信号量-1
printf("Parent++++++++++++++++\n");
sleep(3);
sem_v(semid, 0); //执行V操作,信号量+1
}
}
if (pid == 0)
{
while(1)
{
sem_p(semid, 0); //执行P操作,信号量-1
printf("Child-----------------\n");
sleep(3);
sem_v(semid, 0); //执行V操作,信号量+1
}
}
else
{
perror("Fork error!\n");
}
return 0;
}
//*********************************************信号量pv操作(semaphore)**********************************************
/*2013.10.22.陈顺明*/
// int semop(int semid, struct sembuf *sops, unsigned nsops);
// 作用:改变信号量的键值,Semop调用的一切动作都是一次性完成的,这是为了避免出现因使用了多个信号量而可能发生的竞争现象
// sem_id: 是该信号量的标识码,也就是semget函数的返回值
// sem_ops:是个指向一个结构数值的指针
//unsigned nsops:前一个参数结构体数组的个数
//*********************************************信号量pv操作(semaphore)**********************************************
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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*/
};
int sem_create(key_t key, int num_sems) //创建信号量
{
int semid = semget(key, num_sems, IPC_CREAT |0766);
if (semid < 0)
{
perror("Semaphore creat error!\n");
}
return semid;
}
int sem_open(key_t key, int num_sems) //打开信号量
{
int semid = semget(key, num_sems, 0);
if (semid < 0)
{
perror("Semaphore open error!\n");
}
return semid;
}
int sem_setval(int semid, int sem_num, int value) //设置信号量
{
union semun arg;
arg.val = value;
int ret = semctl(semid, sem_num, SETVAL, arg);
if (ret < 0)
{
perror("Semaphore set value error!\n");
}
return ret;
}
int sem_getval(int semid, int sem_num) //获取信号量
{
int ret = semctl(semid, sem_num, GETVAL);
if (ret < 0)
{
perror("Semaphore get value error!\n");
}
return ret;
}
int sem_setall(int semid, int sem_num, unsigned short *array) //设置所有信号量
{
union semun arg;
arg.array = array;
int ret = semctl(semid, sem_num, SETALL, arg); //sem_num为信号量下标从下标位置开始设置所有信号量(设置起始位置)
if (ret < 0)
{
perror("Semaphore setall value error!\n");
}
return ret;
}
int sem_getall(int semid, int sem_num, unsigned short *array) //获取所有信号量值
{
union semun arg;
arg.array = array;
int ret = semctl(semid, sem_num, GETALL, arg);
if (ret < 0)
{
perror("Semaphore setall value error!\n");
}
return ret;
}
int sem_distory(int semid) //删除信号量
{
int ret = semctl(semid, 0, IPC_RMID);
if (ret < 0)
{
perror("Semaphore delet error!\n");
}
return ret;
}
int sem_p(int semid, int semnum) //信号量P操作
{
struct sembuf buf = {semnum, -1, 0};
int ret = semop(semid, &buf, 1); //最后一个参数1(struct sembuf 数组就一个,如果是buf[2],参数就是2)
if (ret < 0)
{
perror("Semaphore p operate error!\n");
}
return ret;
}
int sem_v(int semid, int semnum) //信号量V操作
{
struct sembuf buf = {semnum, 1, 0};
int ret = semop(semid, &buf, 1);
if (ret < 0)
{
perror("Semaphore V operate error!\n");
}
return ret;
}
//************************************************PV操作的实现******************************************
// int main()
// {
// int semid = sem_create((key_t)3333, 5); //创建信号量,有5组信号量
// sem_setval(semid, 0, 100); //设置下标为0的信号量值为0
//
// sem_v(semid, 0); //执行V操作,信号量+1
// int value = sem_getval(semid, 0); //获取信号量值
// printf("value : %d\n", value); //打印信号量结果value :101
//
// sem_p(semid, 0); //执行P操作,信号量-1
// value = sem_getval(semid, 0); //获取信号量值
// printf("value : %d\n", value); //打印信号量结果value :100
//
//
// sem_distory(semid); //删除信号量
// return 0;
// }
//*****************************************信号量为0,P操作,进程进入堵塞状态****************************
int main()
{
int semid = sem_create((key_t)3333, 5); //创建信号量,有5组信号量
sem_setval(semid, 0, 0); //设置下标为0的信号量值为0
sem_p(semid, 0); //执行P操作,信号量-1(执行的时候进程堵塞)
int value = sem_getval(semid, 0);
printf("value : %d\n", value);
sem_distory(semid);
return 0;
}