信号量
1、 临界资源
同一时刻, 只能被一个进程访问的资源。
2、 临界区
访问临界资源代码区域
3、 原子操作
任何情况下都不能被打断的操作
4、 内核对象
用于对进程间通讯时, 多进程能够访问同一资源的记录。
信号量的作用: 进程间同步控制
信号量相当于记录资源能同时被多少个进程访问。
信号量的操作:
创建或获取: 如果是创建, 必须初始化。 如果获取, 则不能初始化。
减一操作: P 操作
加一操作: V 操作
删除:
int semget((key_t)key, int nsems, int flag); // 创建或者获取
int semop(int semid, struct sembuf *buf, int lenth); // P V 操作
// 初始化和删除
int semctl(int semid, int pos, int cmd, /*union semun un*/);
sem_get(); // 获取信号量, 如果是第一次, 则创建信号量并初始化。
sem_P(); // 执行 P 操作
sem_V(); // 执行 V 操作
sem_del(); // 删除信号量
sem头文件和代码如下
#ifndef __SEM_H
#define __SEM_H
#include
#include
#include
#include
#include
#include
#include
#include
int semid;
union semun
{
int val;
};
void sem_get(); //创建或者获取信号量
void sem_p(); //P操作
void sem_v(); //V操作
void sem_del(); //删除
#endif
#include "sem.h"
void sem_get()
{
semid = semget((key_t)1234, 1, 0664);
if(semid == -1) // 获取失败, 内核中并没有这个信号量集
{
semid = semget((key_t)1234, 1, 0664 | IPC_CREAT);
assert(semid != -1);
//本次获取是创建信号量集,所以必须初始化
union semun v;
v.val = 0;
if(-1 == semctl(semid, 0, SETVAL, v))
{
perror("error");
exit(0);
}
}
}
void sem_p()
{
struct sembuf buff;
buff.sem_num = 0;
buff.sem_op = -1;
buff.sem_flg = SEM_UNDO;
if(-1 == semop(semid, &buff, 1))
{
perror("p error");
exit(0);
}
}
void sem_v()
{
struct sembuf buff;
buff.sem_num = 0;
buff.sem_op = 1;
buff.sem_flg = SEM_UNDO;
if(-1 == semop(semid, &buff, 1))
{
perror("p error");
exit(0);
}
}
void sem_del()
{
if(-1 == semctl(semid, 0, IPC_RMID))
{
perror("del error");
exit(0);
}
}
根据sem代码练习 输入“start”执行输出100以内素数 代码如下
输入start开始
#include
#include
#include
#include
#include
#include
#include
#include"sem.c"
#include"sem.h"
int main()
{
sem_get();
while(1)
{
printf("input:\n");
fflush(stdout);
char buff[128]={0};
fgets(buff,127,stdin);
if(strncmp(buff,"start",5)==0)
{
sem_v();
//printf("start\n");
}
}
}
执行素数
#include
#include
#include"sem.c"
#include"sem.h"
int fun(int n)
{
int flag;
int i;
int j;
for( i=2;i
如图
消息队列
ipcs -s 查看系统上所有的信号量集
ipcrm -s semid 删除系统上的信号量集
ipcs -q 查看系统上所有的消息队列
ipcrm -q msgid 删除系统上的消息队列
ipcs -m 查看系统上所有的共享内存
ipcrm -m shmid 删除系统上的共享内存
A 进程负责循环获取用户输入, 当用户输入“OK” 后, 通知 B 进程打印 100 以内所有的素数。
消息队列
消息: 数据 & 类型
队列: 数据结构, 先进先出
消息队列: 是一种临时存储消息的队列, 完成进程间数据传递, 优先级队列
特点:
与信号量对比: 都以内核对象来确保多进程访问同一个消息队列, 信号量进行进程同步控制, 消息队列发送实际数据。
与管道对比: 管道发送的数据没有类型, 读取数据端无差别从管道中按照数据的前后顺序读取数据, 消息队列数据有类型, 读端可以根据数据类型读取特定数据。
消息队列操作:
创建或获取:
int msgget((key_t)key, int flag);
flag: 权限 以及控制
IPC_CREAT: 如果存在, 直接获取
如果不存在, 则创建
发送消息:
int msgsnd(int msgid, void *ptr, size_t size, int flag);
ptr: ptr 指向一个结构体: 类型 + 数据
size: 数据的大小
获取消息:
int msgrcv(int msgid, void *ptr, size_t size, long type, int flag);
删除消息队列:
int msgctl(int msgid, int cmd, struct msgid_ds * buff);
代码如下
#include
#include
#include
#include
#include
#include
#include
#include
struct msgbuff
{
long type;
char data[128];
};
void main()
{
int msgid = msgget((key_t)1234, IPC_CREAT | 0664);
assert(msgid != -1);
struct msgbuff buff;
buff.type = 1000;
strcpy(buff.data, "hello");
msgsnd(msgid, &buff, strlen(buff.data), 0);
buff.type = 2000;
strcpy(buff.data, "world");
msgsnd(msgid, &buff, strlen(buff.data), 0);
}
#include
#include
#include
#include
#include
#include
#include
#include
struct msgbuff
{
long type;
char data[128];
};
void main()
{
int msgid = msgget((key_t)1234, IPC_CREAT | 0664);
assert(msgid != -1);
struct msgbuff buff;
memset(&buff, 0, sizeof(buff));
msgrcv(msgid, &buff, 127, 1000, 0);
printf("%s\n", buff.data);
}
共享内存
共享内存也有内核对象来管理共享的内存区域
特点: 共享内存是最快的一种 IPC, 在各个进程都有指针直接指向开辟内存区域。 访问时
当做本进程中的一个内存控制直接操作。
操作:
创建或者获取
int shmget((key_t)key, size_t size, int flag);
size: 开辟内存空间的大小,
flag: IPC_CREAT 如果存在, 则获取
如果不存在, 则创建
链接:
void * shmat(int shmid, void *addr, int flag);
返回值一个指向共享内存首地址的指针
断开链接:
int shmdt(void *ptr);
此函数只完成断开链接操作, 并不会删除共享内存。
删除内核对象:
int shmctl(int shmid, int cmd , struct shmid_ds *buff);
注意:
共享内存是两个以上的进程能够操作同一块物理空间的内存区域,所以共享的区域
就成了临界资源, 所以对于共享区域的访问必须做同步控制。(信号量)