目录
1.信号灯集
1.1概念
信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制;
System V信号灯集是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯。
通过信号灯集实现共享内存的同步操作
1.2操作步骤
- 创建key值
- 创建或打开信号灯集 semget
- 初始化信号灯集 semctl
- pv操作 semop
- 删除信号灯集 semctl
1.3函数接口
1.3.1创建信号灯集
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
功能:创建/打开信号灯
参数:key:ftok产生的key值
nsems:信号灯集中包含的信号灯数目
semflg:信号灯集的访问权限,通常为IPC_CREAT |0666
返回值:成功:信号灯集ID
失败:-1
示例:
出现这种情况就是semid等于0了
我们可以手动去删除这个信号灯集:
ipcs -s :查看创建的信号灯集
ipcrm -s [semid]:删除信号灯集
1.3.2初始化或删除信号灯集
int semctl ( int semid, int semnum,int cmd,…/*union semun arg*/);
功能:信号灯集合的控制(初始化/删除)
参数:semid:信号灯集ID
semnum: 要操作的集合中的信号灯编号
cmd:
GETVAL:获取信号灯的值,返回值是获得值
SETVAL:设置信号灯的值,
IPC_RMID:从系统中删除信号灯集合
...:当cmd为SETVAL时,需要传递共用体
返回值:成功 0
失败 -1
共用体格式:
union semun {
int val; /* 信号量的初值 */
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) */
};
示例:
补充:
1.当cmd为SETVAL时需要传递第四个参数,类型为共用体
用法:
union semun {
int val;
};
union semun sem;
sem.val = 10;
semctl(semid, 0, SETVAL, sem); //对编号为0的信号灯设置初值为10
2.当cmd为IPC_RMID时,表示删除信号灯集
用法:semctl(semid, 0, IPC_RMID) // 0:表示信号灯的编号,指定任意一个即可删除
3.当cmd为GETVAL时,表示获取信号灯的值
用法:printf("%d\n", semctl(semid, 0, GETVAL));
1.3.3pv操作
int semop ( int semid, struct sembuf *opsptr, size_t nops);
功能:对信号灯集合中的信号量进行PV操作
参数:semid:信号灯集ID
opsptr:操作方式
nops: 要操作的信号灯的个数 1个
返回值:成功 :0
失败:-1
struct sembuf {
short sem_num; // 要操作的信号灯的编号
short sem_op; // 0 : 等待,直到信号灯的值变成0
// 1 : 释放资源,V操作
// -1 : 分配资源,P操作
short sem_flg; // 0(阻塞),IPC_NOWAIT, SEM_UNDO
};
使用:
申请资源 P操作:
mysembuf.sem_num = 0;
mysembuf.sem_op = -1;
mysembuf.sem_flg = 0;
semop(semid, &mysembuf, 1);
释放资源 V操作:
mysembuf.sem_num = 0;
mysembuf.sem_op = 1;
mysembuf.sem_flg = 0;
semop(semid, &mysembuf, 1);
示例:
优化:将初始化和pv操作封装成函数
进一步优化方案:封装成库
union semun
{
int val;
};
// 初始化
void seminit(int semid, int num, int val)
{
union semun sem;
sem.val = val;
semctl(semid, num, SETVAL, sem);
}
// pv操作
void sem_op(int semid, int num, int op)
{
struct sembuf buf;
buf.sem_num = num;
buf.sem_op = op;
buf.sem_flg = 0;
semop(semid, &buf, 1);
}
1.4操作命令
ipcs -s :查看创建的信号灯集
ipcrm -s [semid]:删除信号灯集
2.消息队列
2.1特点
- 消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等。
- 消息队列可以按照类型来发送/接收消息
- 在linux下消息队列的大小有限制。
- 消息队列个数最多为16个;
- 消息队列总容量最多为16384字节;
- 每个消息内容最多为8192字节。
2.2步骤
- 创建key值
- 创建或打开消息队列 msgget
- 添加消息 msgsnd
- 读取消息 msgrcv
- 删除消息队列 msgctl
2.3函数接口
2.3.1创建消息队列
#include <sys/msg.h>
int msgget(key_t key, int flag);
功能:创建或打开一个消息队列
参数: key值
flag:创建消息队列的权限IPC_CREAT|IPC_EXCL|0666
返回值:成功:msgid
失败:-1
示例:
2.3.2添加消息
int msgsnd(int msqid, const void *msgp, size_t size, int flag);
功能:添加消息
参数:msqid:消息队列的ID
msgp:指向消息的指针。常用消息结构msgbuf如下:
struct msgbuf{
long mtype; //消息类型
char mtext[N]}; //消息正文
}
size:发送的消息正文的字节数
flag:IPC_NOWAIT消息没有发送完成函数也会立即返回
0:直到发送完成函数才返回
返回值:成功:0
失败:-1
示例:
2.3.3读取消息
int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag);
功能:读取消息
参数:msgid:消息队列的ID
msgp:存放读取消息的空间
size:接受的消息正文的字节数
msgtype:0:接收消息队列中第一个消息。
大于0:接收消息队列中第一个类型为msgtyp的消息.
小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息。
flag:0:若无消息函数会一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG
返回值:成功:接收到的消息的长度
失败:-1
示例:
2.3.4删除消息队列
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
功能:对消息队列的操作,删除消息队列
参数:msqid:消息队列的队列ID
cmd:
IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。
IPC_SET:设置消息队列的属性。这个值取自buf参数。
IPC_RMID:从系统中删除消息队列。
buf:消息队列缓冲区
返回值:成功:0
失败:-1
示例:
2.4操作命令
ipcs -q:查看消息队列
ipcrm -q msgid:删除消息队列
cat伪代码
int main()
{
// 打开文件
FILE *fp = fopen(file, "r");
if(fp == NULL)
{
error;
}
while(ch = fgetc(fp) != NULL)
printf(ch);
fclose(fp);
return 0;
}