目录
一、管道
1、匿名管道
有亲缘关系的进程实现进程间通信
#include <unistd.h>
int pipe(int pipefd[2]);
pipefd[0]--->read
pipefd[1]--->write
特点:
1. 半双工通讯
2. 必须凑齐读端和写端
3. 所有写端关闭,read就会返回0
4. 所有读端关闭,write产生SIGPIPE异常,如果此信号忽略,则write返回-1并errno值设置为EPIPE
5. 有容量,写满管道,write会阻塞
6. 读空管道,read会阻塞
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#define BUFSIZE 32
static int cpFl(int rfd, int wfd);
int main(int argc, char *argv[])
{
int fd;
int pfd[2] = {};
pid_t pid;
if (argc < 2)
return 1;
if (-1 == pipe(pfd)) {
perror("pipe()");
exit(1);
}
pid = fork();
if (-1 == pid) {
perror("fork()");
exit(1);
}
if (0 == pid) {
close(pfd[1]);
cpFl(pfd[0], 1);
close(pfd[0]);
exit(0);
}
close(pfd[0]);
fd = open(argv[1], O_RDONLY);
if (-1 == fd) {
perror("open()");
close(pfd[1]);
exit(1);
}
cpFl(fd, pfd[1]);
close(pfd[1]);
close(fd);
wait(NULL);
exit(0);
}
static int cpFl(int rfd, int wfd)
{
char buf[BUFSIZE] = {};
int cnt;
while (1) {
cnt = read(rfd, buf, BUFSIZE);
if (-1 == cnt) {
perror("read()");
return -1;
}
if (0 == cnt)
break;
write(wfd, buf, cnt);
}
return 0;
}
2、命名管道
不仅局限与有亲缘关系的进程,所有的进程都能够操作此管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
可参考mkfifo函数
二、消息队列
就是一个能应用于进程间数据交换的队列,符合队列特点
`int msgget(key_t key, int flags)`
`int msgrcv(int msgid, void *buf, int size, int type, int flag)`
`int msgsnd(int msgid, const void *buf, int size, int flag)`
`int msgctl(int msgid, int cmd, struct msgid_ds *ds)`
三、共享存储
1. shm(是否有亲缘关系都可)
1. 创建
`int shmget(key_t key, int size, int flag)`
2. 映射
`void *shmat(int shmid, const void *addr, int flag)`
`int shmdt(void *addr)`
3. 获得状态/销毁
`int shmctl(int shmid, int cmd, struct shmid_ds *ds)`
2. mmap(仅限于有亲缘关系的进程)
`void *mmap(void *addr, int size, int prot, int flag, int fd, offet_t off)`
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
int main(void)
{
int shmid;
pid_t pid;
char *ptr;
// 创建共享内存
shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | IPC_EXCL | 0600);
if (-1 == shmid) {
perror("shmget()");
exit(1);
}
// 创建子进程
pid = fork();
if (-1 == pid) {
perror("fork()");
goto ERROR;
}
// 各自映射
if (0 == pid) {
ptr = (char *)shmat(shmid, NULL, 0);
if ((void *)-1 == ptr) {
perror("shmat()");
exit(1);
}
strcpy(ptr, "good morning");
shmdt(ptr);
exit(0);
}
wait(NULL);
ptr = shmat(shmid, NULL, 0);
// if error
sleep(10);
puts(ptr);
shmdt(ptr);
// 销毁
shmctl(shmid, IPC_RMID, NULL);
return 0;
ERROR:
shmctl(shmid, IPC_RMID, NULL);
exit(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
// 有亲缘关系的进程得到一端共享内存
int main(void)
{
pid_t pid;
void *ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
pid = fork();
if (-1 == pid) {
perror("fork()");
exit(1);
}
if (0 == pid) {
memcpy(ptr, "good afternoon", 14);
exit(0);
}
wait(NULL);
puts(ptr);
munmap(ptr, 1024);
return 0;
}
四、信号量
保证多进程资源竞争的时候同步