进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、信号、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC
匿名管道
命名管道
是一种特殊文件,文件类型是p,存放于文件系统中
1 2 3
| anki@kong:~$ ls -l total 124972 prwxrwxrwx 1 anki anki 0 Jan 29 22:54 ahhh
|
1 2 3 4 5 6 7 8 9
| #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const char *filename = "/home/anki/ahhh";
pid_t pid; char buff[20];
if((pid = fork()) < 0) { printf("Fork Error!\n"); } else if(pid > 0) { int rs = mkfifo(filename, 0777); if (rs<0 && errno != EEXIST) { perror("create fifo error"); exit(1); } int fd = open(filename, O_WRONLY); for (int i=0; i<10; i++) { write(fd, "hello world", sizeof("hello world")); sleep(1); } close(fd); } else { int fd=open(filename, O_RDONLY); if (fd<0) { perror("open fd failed"); exit(1); } for (int i=0; i<10; i++) { int len=read(fd, buff, 20); cout << len << ":" << buff << endl; } close(fd); }
|
消息队列
存放在内核,由一个标识符来标识
特点
- 面向记录,具有特定格式和特定优先级
- 独立于进程,不会因进程结束而消失
- 可以FIFO,也可以随机读取
1 2 3 4 5 6 7 8 9
| #include <sys/msg.h>
int msgget(key_t key, int flag);
int msgsnd(int msqid, const void *ptr, size_t size, int flag);
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const char *filename = "/home/anki/ahhhh";
pid_t pid;
key_t k = ftok(filename, 10); if (k<0) { perror("ftok failed"); exit(-1); }
if((pid = fork()) < 0) { printf("Fork Error!\n"); } else if(pid > 0) { int msgId = msgget(k, IPC_CREAT|0777); if (msgId<0) { perror("msgget failed"); exit(-1); } message mbuf; mbuf.mtype = 110;
for (int i=0; i<10; i++) { sprintf(mbuf.mtext, "hello world for %d\n", i); msgsnd(msgId, &mbuf, sizeof(mbuf.mtext), 0); } } else { int msgId = msgget(k, IPC_CREAT|0777); if (msgId<0) { perror("msgget failed"); exit(-1); } message mbuf; msgrcv(msgId, &mbuf, 256, 110, 0); cout << mbuf.mtype << ":" << mbuf.mtext << endl; }
|
信号量
- 特点
- 初始>0
- 主要用于进程间的同步/互斥,和共享内存合用可以实现进程间信息通讯
1 2 3 4 5 6 7 8 9 10
| #include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);
int semop(int semid, struct sembuf semoparray[], size_t numops);
int semctl(int semid, int sem_num, int cmd, union semun arg);
|
semop中,sembuf:
1 2 3 4 5 6 7
| struct sembuf { short sem_num; short sem_op; short sem_flg; }
|
semctl中,arg:
1 2 3 4 5 6 7
| union semun { short val; struct semid_ds* buf; unsigned short* array; struct seminfo *buf; } arg;
|
cmd:
cmd |
解释 |
IPC_STAT |
从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中 |
IPC_SET |
设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值 |
IPC_RMID |
从内核中删除信号量集合 |
GETALL |
从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中 |
GETNCNT |
返回当前等待资源的进程个数 |
GETPID |
返回最后一个执行系统调用semop()进程的PID |
GETVAL |
返回信号量集合内单个信号量的值 |
GETZCNT |
返回当前等待100%资源利用的进程个数 |
SETALL |
与GETALL正好相反 |
SETVAL |
用联合体中val成员的值设置信号量集合中单个信号量的值 |
共享内存
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);
void *shmat(int shm_id, const void *addr, int flag);
int shmdt(void *addr);
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
|
参考文章