进程间通信(IPC)
管道:
who | wc -l // who结果写入内核缓存
int pipe(int fds[2]); //两个文件描述符,读和写
一般:
- fds[0] 为读取管道
- fds[1] 为对管道写
- 管道必须读写两端同时打开。
例子:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 int fds[2]; //fds[0]为读,1为写
8 if(pipe(fds)==-1)
9 {
10 perror("pipe"),exit(1);
11 }
12
13 pid_t pid = fork();
14 if(pid == -1)
15 {
16 perror("fork"),exit(1);
17 }
18 else if(pid==0) //子进程写
19 {
20 close(fds[0]); //关闭子进程的读端口
21 write(fds[1],"abcd",4); //向管道写 abcd
22 close(fds[1]); //写完后关闭 写端口
23 exit(0); //正常退出
24 }
25 else if(pid>0) //父进程
26 {
27 close(fds[1]); //关闭父进程写端口
28 char buf[100] = {};
29 int r = read(fds[0],buf,100);//读的内容
30 if(r==0)
31 {
32 printf("read EOF\n");
33 }
34 else if(r==-1)
35 {
36 perror("read"),exit(1);
37 }
38 else if(r>0) //读成功
39 {
40 printf("%s\n",buf);//打印内容
41 close(fds[0]);//关闭读端口
42 exit(0);
43 }
44 }
45 }
命名管道
mkfifo my.p //创建管道文件 大小为0
int mkfifo() //创建管道文件
//打开管道文件
int fd = open(name, O_RDONLY);//读
int fd = open(name, O_WRONLY);//写
//read / write 语义和匿名管道一样
消息队列
int msgget(key_t key, int msgflag);
参数说明:
//相当于文件名 ,是在内核创建的
//打开:0;创建:IPC_CREATE | 0644(权限)
功能:用于创建一个新的或者打开一个已有的消息队列
返回值:消息队列的id,相当于文件描述符
头文件:(sys/msg.h sys/ipc.h)
命令查看:(ipcs -q)
删除IPC对象:(ipcrm -Q key)
系统中最多能够创建多少消息队列:
cat /proc/sys/kernel/msgmni
7543
一条消息最多可以装多少字节:
cat /proc/sys/kernel/msgmni
一个消息队列中所有消息的总字节数:
cat /proc/sys/kernel/msgmnb
例子:创建消息队列
#include<stdio.h>
#include<stdlib.h>
#include<sys/msg.h>
#include<sys/ipc.h>
int main()
{
int msgid = msgget(1357,IPC_CREAT|0644);
if(msgid==-1){
perror("msgget"),exit(1);
}
printf("msgget ok");
}
// 1357的16进制为0x0000054d
——— 消息队列 ———–
键 ———– msqid 拥有者 权限 已用字节数 消息
0x0000054d – 0 — root – 644 ——- 0 ——- 0
往消息队列中发送数据:
int msgsnd(int id, const void *msgp, size_t len, int flag)
参数说明:
//msgget返回值,要发送的消息在哪里,消息的字节数(不包括channel的大小),0
返回值:成功:0;失败: -1
struct msgbuf{
long channel;//消息类型(通道号),必须>=1
//随便,比如自己的消息内容,char mtext[100];
};
例子:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/msg.h>
5 #include<sys/ipc.h>
6
7 struct msgbuf{
8 long mtype;
9 char mtext[1000];
10 };
11
12 int main(int argc, char* argv[])
13 {
14 if(argc!=2)//参数个数不对
15 {
16 fprintf(stderr,"usage:%s type\n", argv[0]);
17 exit(1);
18 }
19
20 int id = msgget(1357,0);//打开一个已有的消息队列,第二个参数为0
21 if(id==-1)//打开失败
22 {
23 perror("msgget"),exit(-1);
24 }
25
26 struct msgbuf mb;//创建消息结构体
27 memset(&mb, 0x00, sizeof(mb));//清空
28
29 mb.mtype = atoi(argv[1]);//将id转换为整形
30 printf("msg: ");
31 fgets(mb.mtext, 999, stdin);
32
33 int res = msgsnd(id, &mb, strlen(mb.mtext), 0);//发送消息
34 if(res==-1)perror("msgsnd"),exit(1);
35 }
从消息队列中取数据
ssize_t msgrcv(int id, void *msggp, size_t len, long mtype, int flag);
参数说明:
//取出来的消息放到这里 装消息的地方的大小(不包括类型)装哪个类型的消息 0
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/msg.h>
5 #include<sys/ipc.h>
6
7 struct msbuf{
8 long mtype;
9 char mtext[1000];
10 };
11
12 int main(int argc, char *argv[])
13 {
14 if(argc!=2)
15 {
16 fprintf(stderr,"usage:%s type\n",argv[0]);
17 exit(-1);
18 }
19
20 int id = msgget(1357,0);//打开消息队列
21 if(id==-1)perror("msgget"),exit(-1);
22
23 struct msbuf mb;
24 memset(&mb,0x00,sizeof(mb));
25
26 if(msgrcv(id,&mb,1000,atoi(argv[1]),0)==-1)//从消息队列读取消息内容
27 perror("msgrcv"),exit(-1);
28
29 printf("%s\n",mb.mtext);
30 }
共享内存
头文件:ipc和shm
创建或打开共享内存:
shmget(key_t key, size_t size,int flag);
参数说明:
//共享内存段大小 //创建IPC_CREATE|0644,打开为0
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/ipc.h>
5 #include<sys/shm.h>
6
7 struct stu{
8 int id;
9 char name[20];
10 };
11
12 int main()
13 {
14 int shmid = shmget(1234,sizeof(struct stu),IPC_CREAT|0644);
15 if(shmid == -1)perror("shmget"),exit(-1);
16 printf("create ok");
17 }
让共享内存和本进程建立关系
void *shmat(int id, char *shmaddr, int flag);
参数说明:
想让操作系统挂到这个地址空间,或者NULL让操作系统自己选择
返回值:实际挂载到的虚拟地址的起始位置
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/ipc.h>
5 #include<sys/shm.h>
6 #include<assert.h>
7 struct stu{
8 int id;
9 char name[20];
10 };
11
12 int main()
13 {
14 int shmid = shmget(1234,sizeof(struct stu),0);
15 if(shmid == -1)perror("shmget"),exit(-1);
16
17 struct stu *p = (struct stu*)shmat(shmid, NULL, 0);
18 assert(p!=NULL);
19
20 p->id = 1;
21 strcpy(p->name,"hello");
22 sleep(3);
23 shmdt(p);
24 }
卸载共享内存:
int shmdt(void *shmadr);
删除共享内存:
int shmctl(int id, int cmd, NULL);
第二个参数://IPC_RMID
PV操作
创建或打开信号量:
int semget(key_t key, int nsems, int flag)
参数说明:后两个参数
//信号量集中信号量的个数 //打开:0 创建:IPC_CREAT|0644
例子:
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<string.h>
int main()
{
int id = semget(1234,1,IPC_CREAT|0644);
if(id==-1)perror("semget"),exit(-1);
printf("create ok\n");
}
设置信号量初值:
int semctl(int id,
int semnum, //信号量集中的第几个信号量
int cmd, //SETVAL
su); //这是信号量初值
union semun{
int val; //value for setval;
}
例子:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 #include<string.h>
6
7 union semun{
8 int val;
9 };
10
11 int main()
12 {
13 int id = semget(1234,0,0);
14 if(id==-1)perror("semget"),exit(-1);
15
16 union semun su;
17 su.val = 5;
18 semctl(id, 0, SETVAL, su);
19 }
设置完,查看信号量的值:
int semctl(int id,
int semnum, //信号量集中的第几个信号量
int cmd, //GETVAL
0);
返回值:当前信号量的值
例子:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 #include<string.h>
6
7 int main()
8 {
9 int id = semget(1234,0,0);
10 if(id==-1)perror("semget"),exit(-1);
11
12 int val = semctl(id,0,GETVAL);
13 printf("%d\n",val);
14 }
PV操作:
int semop(int semid,
struct sembuf sb[],
int len);
struct sembuf{
short sem_num, //信号量的下标
short sem_op, //1 V;-1 P
short sem_flag, //为 0
};
P操作:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 #include<string.h>
6
7 void p(int id)
8 {
9 struct sembuf sb[1];
10 sb[0].sem_num = 0;
11 sb[0].sem_op = -1;
12 sb[0].sem_flg = 0;
13
14 semop(id, sb, 1);
15 }
16
17 int main()
18 {
19 int id = semget(1234,0,0);
20 if(id==-1)perror("semget"),exit(-1);
21
22 p(id);
23 }
V操作:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 #include<string.h>
6
7 void v(int id)
8 {
9 struct sembuf sb[1];
10 sb[0].sem_num = 0;
11 sb[0].sem_op = 1;
12 sb[0].sem_flg = 0;
13
14 semop(id, sb, 1);
15 }
16
17 int main()
18 {
19 int id = semget(1234,0,0);
20 if(id==-1)perror("semget"),exit(-1);
21
22 v(id);
23 }