进程间通信的五种方式:
1.管道(有名管道,无名管道)
2.信号(signal)
3.消息队列
4.共享内存
5.信号量一.管道(有名管道,无名管道)
无名管道:只能在父进程与子进程之间通信
管道的读写其实就是文件的读写操作
void ReadData(int fd)
{
int ret;
char buf[32] = {0};
while (1)
{
ret = read(fd, buf, sizeof(buf));
if (!strcmp(buf, "bye"))
{
break;
}
printf("read from pipe : %s\n", buf);
memset(buf, 0, sizeof(buf));
}
close(fd);
}
void WriteData(int fd)
{
int ret;
char buf[32] = {0};
while (1)
{
scanf("%s", buf);
ret = write(fd, buf, strlen(buf));
if (!strcmp(buf, "bye"))
{
break;
}
memset(buf, 0, sizeof(buf));
}
close(fd);
}
无名管道的创建有两个数组,fd[0]读数据,fd[1]写数据
int main()
{
int ret, fd[2] = {0};
pid_t pid;
ret = pipe(fd); //创建一个无名管道
if (-1 == ret)
{
perror("pipe");
exit(1);
}
pid = fork();
if (-1 == pid)
{
perror("fork");
exit(1);
}
else if (0 == pid)
{
close(fd[1]); //关闭写端口
ReadData(fd[0]); //fd[0]读数据
}
else
{
close(fd[0]); //关闭读端口
int status;
WriteData(fd[1]); //fd[1]写数据
wait(&status);
}
return 0;
}
有名管道:可以在不同的两个进程间通信
写数据.C文件
int main()
{
int ret, fd;
char buf[32] = {0}; //管道写数据
fd = open("fifo.tmp", O_WRONLY);
if (-1 == fd)
{
perror("open");
exit(1);
}
while (1)
{
scanf("%s", buf);
ret = write(fd, buf, strlen(buf));
if (-1 == ret)
{
perror("read");
exit(1);
}
if (!strcmp(buf, "bye"))
{
break;
}
memset(buf, 0, sizeof(buf));
}
close(fd);
return 0;
}
读数据.C文件
int main()
{
int ret, fd;
char buf[32] = {0}; //从管道读取数据
ret = mkfifo("fifo.tmp", 666); //创建有名管道
if (ret == -1)
{
perror("mkfifo");
exit(1);
}
fd = open("fifo.tmp", O_RDONLY);
if (-1 == fd)
{
perror("open");
exit(1);
}
while (1)
{
ret = read(fd, buf, sizeof(buf));
if (-1 == ret)
{
perror("read");
exit(1);
}
if (!strcmp(buf, "bye"))
{
break;
}
printf("%s\n", buf);
memset(buf, 0, sizeof(buf));
}
close(fd);
unlink("fifo.tmp"); //使用完删除管道文件
return 0;
}
二.信号(signal)
相关函数:
1.kill
2.raise(只能给自己发信号)
3.signal(signum,handler)
4.alarm
函数signal(signum,handler)的使用:
void print(int num) //num 信号的值
{
printf("helloworld! %d \n", num);
}
int main()
{
signal(9, SIG_IGN); //当前进程收到信号2的时候,执行print函数
while (1);
return 0;
}
函数alarm的使用:
void print(int num)
{
alarm(1);
printf("helloworld\n");
}
int main()
{
alarm(1);
signal(SIGALRM, print);
while (1);
return 0;
}
三.消息队列
发送.C文件
#define MSGKEY 1234
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[64]; /* message data */
};
int main()
{
struct msgbuf mbuf;
int ret;
int msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL);
if (-1 == msgid)
{
perror("msgget");
exit(1);
}
pid_t pid = fork();
if (-1 == pid)
{
perror("fork");
exit(1);
}
else if (0 == pid) //子进程发送
{
while (1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 1; //消息类型
scanf("%s", mbuf.mtext);
ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
if (-1 == ret)
{
perror("msgsnd");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
mbuf.mtype = 2;
msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
break;
}
}
}
else //父进程接收
{
while (1)
{
memset(&mbuf, 0, sizeof(mbuf));
ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 2, 0);
if (-1 == ret)
{
perror("msgrcv");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
kill(pid, 2);
break;
}
printf("\t\t\t%s\n", mbuf.mtext);
memset(&mbuf, 0, sizeof(mbuf));
}
}
sleep(1);
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
接收.C文件
#define MSGKEY 1234
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[64]; /* message data */
};
int main()
{
struct msgbuf mbuf;
int ret;
int msgid = msgget(MSGKEY, 0);
if (-1 == msgid)
{
perror("msgget");
exit(1);
}
pid_t pid = fork();
if (-1 == pid)
{
perror("fork");
exit(1);
}
else if (0 == pid) //子进程发送
{
while (1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 2; //消息类型
scanf("%s", mbuf.mtext);
ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
if (-1 == ret)
{
perror("msgsnd");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
mbuf.mtype = 1;
msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
break;
}
}
}
else //父进程接收
{
while (1)
{
memset(&mbuf, 0, sizeof(mbuf));
ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 1, 0);
if (-1 == ret)
{
perror("msgrcv");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
kill(pid, 2);
break;
}
printf("\t\t\t%s\n", mbuf.mtext);
memset(&mbuf, 0, sizeof(mbuf));
}
}
return 0;
}
四.共享内存+信号量
//从共享内存中读:
#define SHMKEY 1234
#define SHMSIZE 4096 //以页为单位分配共享内存
#define SEMKEY 1234
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux specific) */
};
void sem_p(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0; //第一个 从0开始
sbuf.sem_op = -1; //p操作
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if (-1 == ret)
{
perror("semop");
return;
}
}
void sem_v(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0; //第一个 从0开始
sbuf.sem_op = 1; //v操作
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if (-1 == ret)
{
perror("semop");
return;
}
}
int main()
{
int shmid, semid, ret;
void *shmaddr;
int count = 0;
shmid = shmget(SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL); //创建共享内存
if (-1 == shmid)
{
perror("shmget");
exit(1);
}
semid = semget(SEMKEY, 1, IPC_CREAT | IPC_EXCL); //创建信号量
if (semid == -1)
{
perror("semget");
exit(1);
}
union semun unsem;
unsem.val = 1; //初始化成二值信号量
ret = semctl(semid, 0, SETVAL, unsem); //初始化信号量
if (-1 == ret)
{
perror("semctl");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0); //映射到虚拟地址空间
if (NULL == shmaddr)
{
perror("shmat");
exit(1);
}
*(int *)shmaddr = count; //数据写到共享内存
while (1)
{
sem_p(semid); //p操作 拔钥匙
count = *(int *)shmaddr; //读取数据
usleep(100000);
if (count >= 100)
{
break;
}
printf("Process A : count = %d\n", count);
count++;
*(int *)shmaddr = count; //写回共享内存
sem_v(semid); //v操作 加一操作 插钥匙
}
shmdt(shmaddr); //解除映射
shmctl(shmid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID);
return 0;
}
//从共享内存中写:
#define SHMKEY 1234
#define SHMSIZE 4096 //以页为单位分配共享内存
#define SEMKEY 1234
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux specific) */
};
void sem_p(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0; //第一个 从0开始
sbuf.sem_op = -1; //p操作
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if (-1 == ret)
{
perror("semop");
return;
}
}
void sem_v(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0; //第一个 从0开始
sbuf.sem_op = 1; //v操作
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if (-1 == ret)
{
perror("semop");
return;
}
}
int main()
{
int shmid, semid, ret;
void *shmaddr;
int count = 0;
shmid = shmget(SHMKEY, SHMSIZE, 0); //创建共享内存
if (-1 == shmid)
{
perror("shmget");
exit(1);
}
semid = semget(SEMKEY, 1, 0); //创建信号量
if (semid == -1)
{
perror("semget");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0); //映射到虚拟地址空间
if (NULL == shmaddr)
{
perror("shmat");
exit(1);
}
while (1)
{
sem_p(semid); //p操作 拔钥匙
count = *(int *)shmaddr; //读取数据
usleep(100000);
if (count >= 100)
{
break;
}
printf("Process B : count = %d\n", count);
count++;
*(int *)shmaddr = count; //写回共享内存
sem_v(semid); //v操作 加一操作 插钥匙
}
shmdt(shmaddr); //解除映射
return 0;
}