Linux c/c++之IPC进程间通信

本文详细介绍了进程间通信(IPC)的三种主要技术:共享内存、消息队列和旗语(信号量)。共享内存允许进程直接访问同一内存区域,提供快速的数据交换;消息队列提供了有序的消息传递,允许不同进程按类型接收数据;旗语(信号量)用于同步和互斥,防止多个进程同时访问资源。文章通过代码示例展示了如何创建、使用和管理这些IPC机制,并探讨了它们的优缺点。
摘要由CSDN通过智能技术生成

 

目录

1. IPC定义

2. 共享内存

2.1 共享内存定义

2.2 shm(共享内存 编程模型)

2.3 shm的一些函数原型

        2.3.1 ftok函数

        2.3.2 shmget函数

        2.3.3 shmat函数

        2.3.4 shmdt函数

        2.3.5 shmctl函数

2.4 共享内存的优势与缺点

        2.4.1 优势

        2.4.2 缺点

 2.5 共享内存示例

         2.5.1 共享内存数据读取端

        2.5.2  共享内存数据发送端

         2.5.3 共享内存段删除端

        2.5.4 运行结果 

3. 消息队列

3.1 消息队列定义

3.2 msg(消息队列 编程模型)

3.3 msg的一些函数原型

        3.3.1 ftok函数

        3.3.2 msgget函数

        3.3.3 msgrcv函数

        3.3.4 msgsnd函数

        3.3.5 msgctl函数

3.4 消息队列的优势与缺点

        3.4.1 优势

        3.4.2 缺点

 3.5 消息队列演示

        3.5.1 消息发送端

        3.5.2 消息接收端

        3.5.3 消息队列删除端

 3.5.6 运行结果

4. 旗语(信号量)

4.1 旗语(信号量定义)

4.2 sem(信号量 编程模型)

4.3 sem的一些函数原型

        4.3.1 ftok函数

        4.3.2 semget函数

        4.3.3 semop函数

        4.3.4 semctl函数

4.4 旗语(信号量)的优势与缺点 

        4.4.1 优势

        4.4.2 缺点

4.5 旗语(信号量演示)

        4.5.1 信号量加端

        4.5.2 信号量减端

        4.5.3 信号量删除

        4.5.4 运行结果

5. 管理IPC的ipc命令簇

5.1 ipcs 查看命令

5.2 ipcrm 删除命令


1. IPC定义

IPC技术: 内核进程通信(Inter Process Communication)

2. 共享内存

2.1 共享内存定义

        shm(share memory),在主机上指定一块内存作为进程之间的共享内存, 不同的进程之间可以通过一些方式去访问这块内存。

2.2 shm(共享内存 编程模型)

  1. 创建key                            ftok函数
  2. 创建共享内存                   shmget函数
  3. 挂载共享内存                   shmat函数
  4. 卸载共享内存                   shmdt函数
  5. 删除共享内存                   shmctl函数

2.3 shm的一些函数原型

        2.3.1 ftok函数

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);

//返回值: 返回值为一个4byte的整数(返回-1失败)
//0--15  bit: pathname的st_ino属性的低16位
//16--23 bit: pathname的st_dev属性的低8位
//24--31 bit: pro_id的低8位

//参数一: 传入一个路径,一般使用当前路径"."
//参数二: 任意的一个整数,因为要做进程间通信,
//那么另一个进程需要与这个数保持一致才能找到对应的ipcid,一般只使用8个bit,因此取值范围在0--255

        2.3.2 shmget函数

//头文件
#include <sys/ipc.h>
#include <sys/shm.h>
//函数原型
int shmget(key_t key, size_t size, int shmflg);

//返回值: 返回一个整数(返回-1失败) 

//参数一: ftok函数的返回值
//参数二: 共享的内存大小(byte)(如果数值为1 -- 4096,实际申请4k(一页))
//参数三: 主要与一些标志有关
// IPC_CREAT  不存在共享内存就创建,否则打开
// IPC_EXCL   不存在共享内存才创建,否则错误

        2.3.3 shmat函数

//头文件
#include <sys/types.h>
#include <sys/shm.h>
//函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg);

//返回值: 返回申请的共享内存的首地址(返回-1则挂载失败)

//参数一: shmget函数的返回值
//参数二: 一般为0,表示连接到一个由内核选择的可用地址之上
//参数三: 一般为0

        2.3.4 shmdt函数

//头文件
#include <sys/types.h>
#include <sys/shm.h>
//函数原型
int shmdt(const void *shmaddr);

//返回值: 成功返回0,失败返回-1
//参数一: shmat函数的返回值

        2.3.5 shmctl函数

//头文件
#include <sys/ipc.h>
#include <sys/shm.h>
//函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

//返回值: 失败返回-1,
//参数一: shmget函数的返回值
//参数二: 设置调用者对共享内存段的权限
// IPC_STAT: 调用者必须对共享内存具有读权限
// IPC_SET: 对shmid_ds 中的某些值做一些修改
// IPC_RMID: 表示销毁某个段
// IPC_INFO: 返回共享内存限制和参数的信息
// SHM_INFO: 返回一个shm_info的结构体
// SHM_STAT: 返回该内存段在内核数组的索引,该数组记录所有共享内存段的信息
// SHM_LOCK: 防止交换共享内存段
// SHM_UNLOCK: 解除防止交换共享内存段
//参数三: 一个指向shmid_ds的结构体指针
struct shmid_ds 
{   struct ipc_perm shm_perm;/*用户权限*/
    size_t shm_segsz;/* segment (bytes)的大小*/
    time_t shm_atime;/*最后连接时间*/
    time_t shm_dtime;/*最后的分离时间时间*/
    time_t ctime;/*上次更改时间*/
    pid_t  shm_cpid;/*创建器的PID*/
    ......
};

2.4 共享内存的优势与缺点

        2.4.1 优势

        因为两个进程可以使用一段内存, 这就构成了进程之间的双向通信, 无疑传输速率是很快的, 是最快的进程间通信方式。因为不同的进程之间是直接从这一段内存之中存放、读取数据。而且使用共享内存进行通信对数据是没有什么限制的。并且共享内存的生命周期与系统内核的生命周期是一致的。

        2.4.2 缺点

        共享内存并没有提供同步机制,在一个进程对共享内存进行写操作结束之前,另一个进程是不能对这块共享内存进行同步访问的,因为我们通常想要实现的是多个进程对共享内存的同步访问。

 2.5 共享内存示例

        使用shmA.c从共享内存中读取数据, shmB.c向共享内存中写入数据, shmctl.c删除共享内存段

         2.5.1 共享内存数据读取端

//shmA.c  读取端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>

int* p = NULL;
void hand(){
	//5.卸载功能共享内存
	shmdt(p);
	printf("bye bye!\n");

	exit(0);
}
int main(){
	signal(SIGINT,hand);
	//1.创建key
	key_t key = ftok(".",'m');  //参数二在256之内
	if(-1 == key) printf("create key error:%m\n"),exit(-1);
	printf("create key success!\n");
	//2.创建共享内存   内存单位之页   1页 == 4k
	int shmid = shmget(key,4096,IPC_CREAT);
	if(-1 == shmid) printf("shmget error:%m\n"),exit(-1);
	printf("shmget success!\n");
	//3.挂载共享内存
	p = (int*)shmat(shmid,NULL,0);
	if((int*)-1 == p) printf("shmat error:%m\n"),exit(-1);
	printf("shmat success!\n");
	//4.使用共享内存
	while(1){
		printf("%d\n",*p);
		sleep(1);
	}

	return 0;
}

        2.5.2  共享内存数据发送端

//shmB.c  写入端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>

int* p = NULL;
void hand(){
	//5.卸载功能共享内存
	shmdt(p);
	printf("bye bye!\n");

	exit(0);
}
int main(){
	signal(SIGINT,hand);
	//1.创建key
	key_t key = ftok(".",'m');  //参数二在256之内
	if(-1 == key) printf("create key error:%m\n"),exit(-1);
	printf("create key success!\n");
	//2.获取共享内存  
	int shmid = shmget(key,4096,IPC_CREAT);
	if(-1 == shmid) printf("shmget error:%m\n"),exit(-1);
	printf("shmget success!\n");
	//3.挂载共享内存
	p = (int*)shmat(shmid,NULL,0);
	if(NULL == p) printf("shmat error:%m\n"),exit(-1);
	printf("shmat success!\n");
	//4.使用共享内存
	int n = 0;
	while(1){
		*p = n++;
		sleep(1);
	}

	return 0;
}

         2.5.3 共享内存段删除端

//shmctl.c  删除共享内存
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(){
	//1.创建key
	key_t key = ftok(".",'m');  //参数二在256之内
	if(-1 == key) printf("create key error:%m\n"),exit(-1);
	printf("create key success!\n");
	//2.获取共享内存  
	int shmid = shmget(key,4096,IPC_CREAT);
	if(-1 == shmid) printf("shmget error:%m\n"),exit(-1);
	printf("shmget success!\n");

	//3.删除共享内存
	shmctl(shmid,IPC_RMID,NULL);

	return 0;
}

        2.5.4 运行结果 

 shmA读取数据进程端单独运行:

 shmA读取数据进程端与shmB写入数据进程端同时运行:

 

 ipcs -m 命令查看当前共享内存信息:

 使用shmctl删除当前创建的共享内存段后:

3. 消息队列

3.1 消息队列定义

        msg(message queue), 在主机上指定一个或者多个队列, 一方进程向队列之中放数据, 另一方从队列之中拿东西。

3.2 msg(消息队列 编程模型)

  1. 创建key                             ftok函数
  2. 创建消息队列                    msgget函数
  3. 收发消息                           msgrcv 函数       msgsnd 函数
  4. 删除消息队列                    msgctl函数

3.3 msg的一些函数原型

        3.3.1 ftok函数

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);

//返回值: 返回值为一个4byte的整数(返回-1失败)
//0--15  bit: pathname的st_ino属性的低16位
//16--23 bit: pathname的st_dev属性的低8位
//24--31 bit: pro_id的低8位

//参数一: 传入一个路径,一般使用当前路径"."
//参数二: 任意的一个整数,因为要做进程间通信,
//那么另一个进程需要与这个数保持一致才能找到对应的ipcid,一般只使用8个bit,因此取值范围在0--255

        3.3.2 msgget函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

//返回值: 返回一个整数(-1表示失败)
//参数一: ftok函数的返回值
//参数二: 主要是一些标志
// IPC_CREAT  不存在共享内存就创建,否则打开
// IPC_EXCL   不存在共享内存才创建,否则错误

        3.3.3 msgrcv函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

//返回值: (失败返回-1)返回实际复制到mtext数组中的字节数
//参数一: msgget函数的返回值
//参数二: 指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构
    struct msgbuf {
        long mtype;    
        char mtext[1];  //可以是1,也可以是其它数
    };
//参数三: 消息的大小
//参数四: 从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都会被读取。
//参数五: 用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常数IPC_NOWAIT合用,则在消息队列呈空时,不做等待马上返回-1,并设定错误码为ENOMSG。

        3.3.4 msgsnd函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

//返回值: (失败返回-1)成功返回0
//参数一: msgget函数的返回值
//参数二: 指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构
    struct msgbuf {
        long mtype;    
        char mtext[1];  //可以是1,也可以是其它数
    };
//参数三: 消息的大小
//参数四: 用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常数IPC_NOWAIT合用,则在msgsnd()执行时若是消息队列已满,则msgsnd()将不会阻塞,而会立即返回-1。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取阻塞等待的处理模式。

        3.3.5 msgctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

//返回值: 失败返回-1,
//参数一: shmget函数的返回值
//参数二: 设置调用者对共享内存段的权限
// IPC_STAT: 调用者必须对共享内存具有读权限
// IPC_SET: 对msqid_ds 中的某些值做一些修改
// IPC_RMID: 表示销毁某个段
// IPC_INFO: 返回共享内存限制和参数的信息
// MSG_INFO: 返回一个msginfo的结构体
// MSG_STAT: 返回该内存段在内核数组的索引,该数组记录所有共享内存段的信息
//参数三: 一个指向msqid_ds 的结构体指针
struct msqid_ds {
               struct ipc_perm msg_perm;     /* 所有权和权限 */
               time_t          msg_stime;    /* 最后一次 msgsnd(2) */
               time_t          msg_rtime;    /* 最后一次 msgrcv(2) */
               time_t          msg_ctime;    /* 最后一次修改的时间*/
               unsigned long   __msg_cbytes; /* 当前队列的字节数(非标准) */
               msgqnum_t       msg_qnum;     /* 当前队列中的消息数 */
               msglen_t        msg_qbytes;   /* 队列允许的最大字节数 */
               pid_t           msg_lspid;    /* 上一次 msgsnd(2) 的PID*/
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

3.4 消息队列的优势与缺点

        3.4.1 优势

         消息队列提供了一种从进程向另一个进程发送一个数据块的方法。每个数据块都被认为是一个类型,接收进程接收的数据块可以有不同的类型值。可以通过发送消息来避免命名管道的同步和阻塞的问题。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。 

        3.4.2 缺点

         每个数据块有大小限制, 整个操作系统中所有的数据块总大小也有一个限制。

 3.5 消息队列演示

        3.5.1 消息发送端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

//发送端进程
struct msgbuf{
	long type;
	char buff[20];
};
int main(){
	struct msgbuf msg;
	//1.创建key
	key_t key = ftok(".",'q');
	if(-1 == key) printf("ftok error:%m\n"),exit(-1);
	printf("ftok success!\n");
	//2. 创建消息队列
	int msgid = msgget(key,IPC_CREAT | 0666);
	if(-1 == msgid) printf("msgget error:%m\n"),exit(-1);
	printf("msgget success!\n");
	//3. 发消息
	int r;
	while(1){
		printf("请输入消息类型:");
		scanf("%ld",&msg.type);
		printf("请输入消息内容:");
		scanf("%s",msg.buff);
		r = msgsnd(msgid,&msg,sizeof(msg),IPC_NOWAIT); //IPC_NOWAIT非阻塞方式
		printf("r: %d\n",r);
	}


	return 0;
}

        3.5.2 消息接收端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

#define TYPE 2
//接收端进程
struct msgbuf{
	long type;
	char buff[20];
};
int main(){
	struct msgbuf msg;
	msg.type = TYPE;
	//1.创建key
	key_t key = ftok(".",'q');
	if(-1 == key) printf("ftok error:%m\n"),exit(-1);
	printf("ftok success!\n");
	//2. 创建消息队列
	int msgid = msgget(key,IPC_CREAT | 0666);
	if(-1 == msgid) printf("msgget error:%m\n"),exit(-1);
	printf("msgget success!\n");
	//3. 接收消息
	int r;
	while(1){
		memset(msg.buff,0,20);
		r = msgrcv(msgid,&msg,sizeof(msg),TYPE,IPC_NOWAIT);
		printf("r:%d msg:%s type:%ld\n", r, msg.buff, msg.type);
		sleep(1);
	}
	return 0;
}

        3.5.3 消息队列删除端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

int main(){
	//1.创建key
	key_t key = ftok(".",'q');
	if(-1 == key) printf("ftok error:%m\n"),exit(-1);
	printf("ftok success!\n");
	//2. 创建消息队列
	int msgid = msgget(key,IPC_CREAT | 0666);
	if(-1 == msgid) printf("msgget error:%m\n"),exit(-1);
	printf("msgget success!\n");
	//3. 删除当前消息队列
	msgctl(msgid,IPC_RMID,NULL);


	return 0;
}

 3.5.6 运行结果

        当发送端的消息类型是type = 2 时, 接收端将消息队列中 type为2的消息取出来处理, type为3的消息仍然在消息队列中 

 

        使用命令查看创建的消息队列 (已用字节数是刚刚的type为3的消息)

   

       继续发送一个type为5的消息和一个type为6的消息,发现已用字节数变成了96 

 

       删除消息队列后

  

 

 

4. 旗语(信号量)

4.1 旗语(信号量定义)

sem(semaphore), 让多个进程不可能同时访问一块区域

4.2 sem(信号量 编程模型)

  1. 创建key                                  ftok函数
  2. 创建旗语(信号量)                   semget函数
  3. 初始化旗语(信号量)               semctl函数
  4. 使用旗语(信号量)                   semop函数
  5. 删除旗语(信号量)                   semctl函数

4.3 sem的一些函数原型

        4.3.1 ftok函数

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char *pathname, int proj_id);

//返回值: 返回值为一个4byte的整数(返回-1失败)
//0--15  bit: pathname的st_ino属性的低16位
//16--23 bit: pathname的st_dev属性的低8位
//24--31 bit: pro_id的低8位

//参数一: 传入一个路径,一般使用当前路径"."
//参数二: 任意的一个整数,因为要做进程间通信,
//那么另一个进程需要与这个数保持一致才能找到对应的ipcid,一般只使用8个bit,因此取值范围在0--255

        4.3.2 semget函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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

//返回值: 返回一个整数(-1表示失败)
//参数一: ftok函数返回值
//参数二: 创建信号量的个数(一般创建一个)
//参数三: 主要是一些标志
// IPC_CREAT  不存在共享内存就创建,否则打开
// IPC_EXCL   不存在共享内存才创建,否则错误

        4.3.3 semop函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, size_t nsops);

//返回值: 成功返回0, 失败返回-1
//参数一: semget函数返回值()
//参数二: 信号量的一些信息(用户可更改)
sops[0].sem_num = 0; 信号量的索引
sops[0].sem_op = 0;  加还是减以及加减的值
sops[0].sem_flg = 0; 一般设置为0
//参数三: 操作的次数

        4.3.4 semctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

//返回值: 失败返回-1
//参数一: semget函数返回值(信号量的标识id)
//参数二: 信号量的标识,标识使用第几个信号量(从0开始)
//参数三: 一个指向msqid_ds 的结构体指针
// IPC_STAT: 调用者必须对共享内存具有读权限
// IPC_SET: 对semid_ds 中的某些值做一些修改
// IPC_RMID: 表示销毁某个段
// IPC_INFO: 返回共享内存限制和参数的信息
// SEM_INFO: 返回一个seminfo的结构体
// SEM_STAT: 返回该内存段在内核数组的索引,该数组记录所有共享内存段的信息
// GETALL:   获取集合中所有的信号量
// GETNCNT:  返回集合中指定semnum的信号量
// GETPID:   返回指定semnum的sempid的值
// GETVAL:   返回指定semnum的semval的值
// GETZCNT:  返回集合中第一个信号量的semzcnt值
// SETALL:   为集合中所有信号量设置值
// SETVAL:   设置一个信号量的值
//参数四: 缺省参数, union semun类型的指针
 union semun {
               int              val;    /* 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*/
           };

4.4 旗语(信号量)的优势与缺点 

        4.4.1 优势

         节省了打开文件以及关闭文件的时间,数据传输速率提高

        4.4.2 缺点

         一但被锁定, 在解锁之前出现程序崩溃等问题, 就会导致锁定的信号量无法恢复, 形成永久性的占用, 使用文件操作的方式则不会出现这种情况, 因为在进程退出的时候, 文件就会被关闭, 在该文件描述符上的锁定就会被自动解除。

4.5 旗语(信号量演示)

        4.5.1 信号量加端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(){
	//1. 创建key
	key_t key = ftok(".",'s');
	if(-1 == key) printf("ftok error:%m\n"),exit(-1);
	printf("ftok success!\n");
	//2. 创建信号量
	int semid = semget(key,1,IPC_CREAT | 0654);
	if(-1 == semid) printf("semget error:%m\n"),exit(-1);
	printf("semget success!\n");

	//3. 使用旗语
	struct sembuf buf;
	buf.sem_num = 0;
	buf.sem_op = 1;     //加
	buf.sem_flg = 0;

	while(1){
		semop(semid,&buf,1); //操作一次
		sleep(1);
	}


	return 0;
}

        4.5.2 信号量减端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun{
	int val;
	struct semid_ds* buf;
	unsigned short* array;
	struct seminfo* __buf;
};
int main(){
	//1. 创建key
	key_t key = ftok(".",'s');
	if(-1 == key) printf("ftok error:%m\n"),exit(-1);
	printf("ftok success!\n");
	//2. 创建信号量
	int semid = semget(key,1,IPC_CREAT | 0654);
	if(-1 == semid) printf("semget error:%m\n"),exit(-1);
	printf("semget success!\n");
	//3. 初始化信号量
	union semun u;
	u.val = 5;
	semctl(semid,0,SETVAL,u);
	//4. 使用旗语
	struct sembuf buf;
	buf.sem_num = 0;
	buf.sem_op = -1;    //减
	buf.sem_flg = 0;

	int n = 0;
	while(1){
		printf("卖出%d辆!\n",++n);
		semop(semid,&buf,1); //操作一次
	}

	return 0;
}

        4.5.3 信号量删除

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <signal.h>

int main(){
	//1. 创建key
	key_t key = ftok(".",'s');
	if(-1 == key) printf("ftok error:%m\n"),exit(-1);
	printf("ftok success!\n");
	//2. 创建信号量
	int semid = semget(key,1,IPC_CREAT | 0654);
	if(-1 == semid) printf("semget error:%m\n"),exit(-1);
	printf("semget success!\n");

	//3. 删除旗语
	semctl(semid,0,IPC_RMID,NULL);

	return 0;
}

        4.5.4 运行结果

                设置信号量 0 初始值为5, 运行A后,再运行B: 

        

                 ipcs -s 查看信号量信息:

        

                删除创建的信号量后,ipcs -s 查看信号量信息:

       

 

5. 管理IPC的ipc命令簇

5.1 ipcs 查看命令

  1.   -m   查看shm(共享内存)
  2.   -q    查看msg(消息队列)
  3.   -s    查看sem(信号量)

5.2 ipcrm 删除命令

  1.  -m  删除shm(共享内存)
  2.  -q   删除msg(消息队列)
  3.   -s  删除sem(信号量)

注: shm   msg   sem 都必须先有一个key(key是根据fd来创建的)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

石小浪♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值