信号:
同步:发送方发送数据,等待接受方响应之后才发下一个数据包的通讯方式
异步:发送方发送数据,不等待接送方发回相应,接着发送下一个数据包的通讯方式
1.特点:
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
2.基本概念:
发送信号:产生信号的方式有很多种,
(1).一个进程可以给一个进程发送一个特定信号, kill -9 进程ID号
(2).内核可以向用户进程发送信号 管道断裂 alarm(2)
(3).组合键
ctrl + c— SIGINT
ctrl+z ----SIGSTOP
ctrl+\ —SIFQUIT
(4).自己可以给自己发送信号 raise()
接受信号后处理信号
(1).忽略信号
(2).使用默认方式处理
(3).捕获信号(安装信号):获得该信号之后,不让他执行默认的操作,可以去执行别的程序,
但有两个信号是不能被安装也不能被忽略,SIGSTOP SIGKILL
3.使用的函数:
#include <signal.h>
int raise(int sig);
#include <unistd.h>
参数1:秒数
时间到了之后内核会给程序发送SIGALRM
unsigned int alarm(unsigned int seconds);
#include <signal.h>
typedef void (*sighandler_t)(int);
参数1是要接收到信号的id
参数2:
(1).忽略该信号 SIG_IGN
(2). 使用默认处理方式 SIG_DFL
(3). 捕获处理(安装信号)
sighandler_t signal(int signum, sighandler_t handler); 捕获信号(安装信号)
接收到的信号之后,对信号进行处理:
systemV IPC对象
ipcs -----查看系统5的IPC对象
1.特点:
每个IPC对象有唯一的ID值,由系统分配的
每个IPC对象有一个关联的key值(ftok函数)
key值为0表示私有对象,若key非0和ID值一一对应
2.获得key值
消息队列,共享内存都需要获得key值
#include <sys/types.h>
#include <sys/ipc.h>
参数1:path存在且可访问的文件路径
参数2: 不能为0
返回值:成功返回key值,失败返回-1
key_t ftok(const char *pathname, int proj_id);
3.消息队列:
1.特点:
1.是一种特殊的链表队列,满足先入先出
2.消息队列是按照类型来发送/接受信息
2.使用的函数
打开和创建消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
参数1:通过ftok获得key
参数2:
IPC_CREAT |0600如果key不存在,则创建,若存在,返回id中
IPC_EXCL 如果key在,返回失败
IPC_NOWAIT 非阻塞
返回值:成功返回消息队列代号.失败返回-1
int msgget(key_t key, int msgflg);
读写数据
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
参数1:msgget获得的id值
参数2:自定义的结构体,
struct msgBuf{
long mtype; 消息队列的类型
char mtext[100]; 数据
}
参数3:发送消息的字节数
参数4:0 消息发送成功返回,无空间阻塞
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数1:msgget获得的id值
参数2:自定义的结构体,
struct msgBuf{
long mtype; 消息队列的类型
char mtext[100]; 数据
}
参数3:发送消息的字节数
参数4:接送数据的类型
参数5: 消息发送成功返回,无空间阻塞
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
控制消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
参数1:msgget获得ip的值
参数2: IPC_RMID 删除
IPC_SET 设置参数
IPC_STAT 获得参数
参数3:一般为NULL
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//定义结构消息队列中的结构体数据类型并取别名
typedef struct msgbuf
{
long mtype; //消息的类型
char mtext[100]; //消息的数据
}Msg;
int main(void)
{
//1.获得key值
key_t key=0;
key=ftok("./",1);
if(key<0)
{
printf("key error");
return -1;
}
printf("key=%d\n",key);
//2.获得消息队列代号
int msgid=0;
msgid=msgget(key,IPC_CREAT|0600);
if(msgid<0)
{
perror("msgget error");
return -1;
}
Msg msgA,msgB;
msgA.mtype=1;
msgB.mtype=2;
while(1)
{
printf("A:");
scanf("%s",msgA.mtext);
//将类型发送给对方
//参数1:msgget获得id 参数2:发送数据的首地址,参数3:大小,参数4
msgsnd(msgid,&msgA,sizeof(msgA),0);
memset(&msgB,'\0',sizeof(msgB));
msgrcv(msgid,&msgB,sizeof(msgB),msgB.mtype,0);
printf("B:%s\n",msgB.mtext);
}
//删除ipcs
//参数1:msgget获得的id
//参数2:IPC_RMID 表示删除
//参数3:NULL
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//定义结构消息队列中的结构体数据类型并取别名
typedef struct msgbuf
{
long mtype; //消息的类型
char mtext[100]; //消息的数据
}Msg;
int main(void)
{
//1.获得key值
//2.获得消息队列代号
//3,读取消息
//4.删除消息队列
//1.获得key值
key_t key=0;
key=ftok("./",1);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.获得消息队列代号
int msgid=0;
msgid=msgget(key,IPC_CREAT|0600);
if(msgid<0)
{
perror("msgget error");
return -1;
}
//3,读取消息
Msg msgA;
msgA.mtype=1;
Msg msgB;
msgB.mtype=2;
while(1)
{
//参数1:msgget获得的id
//参数2:读取结构体的地址
//参数3:读取的大小
//参数4:读取的类型
//参数5:0
memset(&msgA,'\0',sizeof(msgA));
msgrcv(msgid,&msgA,sizeof(msgA),msgA.mtype,0);
printf("A:%s\n",msgA.mtext);
printf("B:");
scanf("%s",msgB.mtext);
msgsnd(msgid,&msgB,sizeof(msgB),0);
}
//4.删除消息队列
msgctl(msgid,IPC_RMID,NULL);
}
4.共享内存
1.特点:
共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,
共享内存是在内核空间创建,需要将内核共享内存区映射到用户进程中
由于多个进程可同时访问共享内存,因此需要同步(信号量)和互斥机制来配合
2.使用的函数
shmget函数:
#include <sys/ipc.h>
#include <sys/shm.h>
/*
函数名:shmget
函数功能:获得共享内存
函数参数:key:共享内存的键值,多个进程可以通过它访问同一个共享内存。ftok()获得
其中有个特殊值 IPC_PRIVATE,用于创建当前进程的私有共享内存。
size:共享内存的大小
shmflg:同open()函数的权限位,也可以使用八进制表示法
IPC_CREAT|0666
不管是否已存在该块共享内存,则都会返回共享内存的ID,若不存在则新建
IPC_EXCL
不管有没有该块共享内存,返回-1
函数返回值:
成功:共享内存段标识符
失败:-1
*/
int shmget(key_t key, size_t size, int shmflg);
shmat函数:
#include <sys/types.h>
#include <sys/shm.h>
函数参数:
shmid:要映射的共享内存区标识符。
shmaddr:将共享内存映射到指定地址若为NULL,则表示系统自动分配地址,并把该段共享,内存映射到调用进程的地址空间)
shmflg:SHM_RDONLY:共享内存只读
默认0:共享内存可读可写
函数返回值:成功:被映射的段地址
出错:-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmdt函数:
#include <sys/types.h>
#include <sys/shm.h>
函数原型:int shmdt(const void *shmaddr);
函数参数:shmaddr:被映射的共享内存段地址
函数返回值:
成功:0
失败:-1
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函数参数: 参数1:shmid:要映射的共享内存区标识符。
参数2:
IPC_RMID 表示删除
IPC_SET 设置参数
IPC_STAT 获得参数
参数3:NULL
函数返回值:
成功:0
失败:-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(void)
{
//1.通过ftok获得key
//2.创建共享内存 shmget
//3.将共享内存映射到具体的进程空间 shmat
//4.读写
//5.分离共享内存
//6.删除共享内存
//1.通过ftok获得key
key_t key=0;
key=ftok("./",12);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.创建共享内存 shmget
int shmid=0;
shmid=shmget(key,1024,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
return -1;
}
//3.将共享内存映射到具体的进程空间 shmat
char * pShm=NULL;
pShm=shmat(shmid,NULL,0);
//4.读写
memset(pShm,'\0',pShm);
strcpy(pShm,"helloworld");
//5.分离共享内存
shmdt(pShm);
//6.删除共享内存
shmctl(shmid,IPC_CREAT,NULL);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(void)
{
//1.通过ftok获得key
//2.创建共享内存 shmget
//3.将共享内存映射到具体的进程空间 shmat
//4.读写
//5.分离共享内存
//6.删除共享内存
//1.通过ftok获得key
key_t key=0;
key=ftok("./",12);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.创建共享内存 shmget
int shmid=0;
shmid=shmget(key,1024,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
return -1;
}
//3.将共享内存映射到具体的进程空间 shmat
char * pShm=NULL;
pShm=shmat(shmid,NULL,0);
//4.读写
sleep(5);
printf("%s",pShm);
//5.分离共享内存
shmdt(pShm);
//6.删除共享内存
shmctl(shmid,IPC_CREAT,NULL);
return 0;
}
5.信号量
共享内存------公共区域
1.实现进程间的同步
和共享内存配合使用,帮助共享内存实现同步
1 2 3 4 5 6 7 8
多个线程: 买菜----择菜 -----洗菜-----切菜----炒菜—端菜----收盘—洗盘
2.工作原理:
二值信号灯:
值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。
计数信号灯:
值在0到n之间。用来统计资源,其值代表可用资源数
等待操作是等待信号灯的值变为大于0,然后将其减1;而释放操作则相反,用来唤醒等待资源的进程或者线程
2.使用的函数
sem_open:
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
sem_t *sem_open(const char *pathname, int oflag);
/*
*函数名:sem_open
*函数功能:打开一个信号量,如果信号量不存在,则创建信号量
*函数参数:
* const char *pathname:信号量的名字(标识)
* int oflag:同文件IO的创建时的权限
* O_CREAT | O_RDWR
* mode_t mode:同文件权限
* unsigned in value:信号量的初始值
*函数返回值:sem_t *:成功返回信号量操作对象的指针
*/
sem_t *sem_open(const char pathname, int oflag, mode_t mode, unsigned int value);
sem_getvalue:
#include <semaphore.h>
/
*函数名:sem_getvalue
*函数功能:获取当前信号量的值
*函数参数:
* sem_t *sem:信号量的操作指针
* int *sval:存储信号量值得内存首地址
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_getvalue(sem_t *sem, int sval);
sem_wait:
#include <semaphore.h>
/
*函数名:sem_wait
*函数功能:信号量值减一
*函数参数:sem_t *sem:信号量的操作指针
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_wait(sem_t sem);
sem_post:
#include <semaphore.h>
/
*函数名:sem_post
*函数功能:信号量值加一
*函数参数:sem_t *sem:信号量的操作指针
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_post(sem_t sem);
sem_close:
#include <semaphore.h>
/
*函数名:sem_close
*函数功能:关闭一个有名信号量
*函数参数:sem_t *sem:信号量的操作指针
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_close(sem_t *sem);
注意:进程中使用的信号量,称之为有名信号量
编译时链接库 -lpthread
头文件.h
#ifndef _SHM_H
#define _SHM_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#endif
#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
//1.通过ftok获得key
//2.创建共享内存 shmget
//3.将共享内存映射到具体的进程空间 shmat
//4.读写
//5.分离共享内存
//6.删除共享内存
//1.通过ftok获得key
key_t key=0;
key=ftok("./",12);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.创建共享内存 shmget
int shmid=0;
shmid=shmget(key,1024,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
return -1;
}
//3.将共享内存映射到具体的进程空间 shmat
char * pShm=NULL;
pShm=shmat(shmid,NULL,0);
//1-1.打开信号登,设置初值 4
sem_t *mySem;
mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
if(NULL==mySem)
{
perror("sem_open error");
}
while(1){
sleep(3);
//1-2.获得当前信号量的值
int sem_v;
sem_getvalue(mySem,&sem_v);
// printf("sem_v=%d\n",sem_v);
if(sem_v==5){
//1-3.将信号量的值减1
sem_wait(mySem);
printf("%s\n",pShm);
//4.读写
memset(pShm,'\0',1024);
strcpy(pShm,"买菜");
}
}
//5.分离共享内存
shmdt(pShm);
//6.删除共享内存
shmctl(shmid,IPC_CREAT,NULL);
return 0;
}
#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
//1.通过ftok获得key
//2.创建共享内存 shmget
//3.将共享内存映射到具体的进程空间 shmat
//4.读写
//5.分离共享内存
//6.删除共享内存
//1.通过ftok获得key
key_t key=0;
key=ftok("./",12);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.创建共享内存 shmget
int shmid=0;
shmid=shmget(key,1024,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
return -1;
}
//3.将共享内存映射到具体的进程空间 shmat
char * pShm=NULL;
pShm=shmat(shmid,NULL,0);
//1-1.打开信号登,设置初值 4
sem_t *mySem;
mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
if(NULL==mySem)
{
perror("sem_open error");
}
while(1){
sleep(2);
//1-2.获得当前信号量的值
int sem_v;
sem_getvalue(mySem,&sem_v);
//printf("sem_v=%d\n",sem_v);
if(sem_v==4){
//1-3.将信号量的值减1
sem_wait(mySem);
printf("p2:%s\n",pShm);
//4.读写
memset(pShm,'\0',1024);
strcpy(pShm,"择菜");
}
}
//5.分离共享内存
shmdt(pShm);
//6.删除共享内存
shmctl(shmid,IPC_CREAT,NULL);
return 0;
}
#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
//1.通过ftok获得key
//2.创建共享内存 shmget
//3.将共享内存映射到具体的进程空间 shmat
//4.读写
//5.分离共享内存
//6.删除共享内存
//1.通过ftok获得key
key_t key=0;
key=ftok("./",12);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.创建共享内存 shmget
int shmid=0;
shmid=shmget(key,1024,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
return -1;
}
//3.将共享内存映射到具体的进程空间 shmat
char * pShm=NULL;
pShm=shmat(shmid,NULL,0);
//1-1.打开信号登,设置初值 4
sem_t *mySem;
mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
if(NULL==mySem)
{
perror("sem_open error");
}
while(1){
sleep(3);
//1-2.获得当前信号量的值
int sem_v;
sem_getvalue(mySem,&sem_v);
// printf("sem_v=%d\n",sem_v);
if(sem_v==3){
//1-3.将信号量的值减1
sem_wait(mySem);
printf("%s\n",pShm);
//4.读写
memset(pShm,'\0',1024);
strcpy(pShm,"洗菜");
}
}
//5.分离共享内存
shmdt(pShm);
//6.删除共享内存
shmctl(shmid,IPC_CREAT,NULL);
return 0;
}
#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
//1.通过ftok获得key
//2.创建共享内存 shmget
//3.将共享内存映射到具体的进程空间 shmat
//4.读写
//5.分离共享内存
//6.删除共享内存
//1.通过ftok获得key
key_t key=0;
key=ftok("./",12);
if(key<0)
{
perror("ftok error");
return -1;
}
//2.创建共享内存 shmget
int shmid=0;
shmid=shmget(key,1024,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
return -1;
}
//3.将共享内存映射到具体的进程空间 shmat
char * pShm=NULL;
pShm=shmat(shmid,NULL,0);
//1-1.打开信号登,设置初值 4
sem_t *mySem;
mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
if(NULL==mySem)
{
perror("sem_open error");
}
while(1){
sleep(3);
//1-2.获得当前信号量的值
int sem_v;
sem_getvalue(mySem,&sem_v);
//printf("sem_v=%d\n",sem_v);
if(sem_v==2){
//1-3.将信号量的值减1
sem_wait(mySem);
printf("%s\n",pShm);
//4.读写
memset(pShm,'\0',1024);
strcpy(pShm,"切菜");
sem_post(mySem);
sem_post(mySem);
sem_post(mySem);
sem_post(mySem);
}
}
//5.分离共享内存
shmdt(pShm);
//6.删除共享内存
shmctl(shmid,IPC_CREAT,NULL);
return 0;
}
补充