进程间通信和同步:pipe、FIFO、消息队列、信号量、共享内存、信号
一、半双工管道(pipe)

关于管道详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3560130.html。
1、管道实现父子进程间通信实例:
/* pipe.c */
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#define MAXLINE 1024
int
main(void)
{
int fd[2], pid;
char buf[MAXLINE]; if(pipe(fd) < 0)
{
perror("pipe error");
exit(1);
} if((pid = fork()) < 0)
{
perror("fork error");
exit(1);
}
else if(pid == 0) /* child */
{
close(fd[1]); /* read from parent */ if(read(fd[0], buf, MAXLINE) < 0)
{
perror("read error");
exit(1);
}
printf("read from parent: %s\n", buf);
}
else /* parent */
{
close(fd[0]); /* send to child */ if(write(fd[1], "hello, i am your parent", 24) != 24)
{
perror("write error");
exit(1);
}
printf("send to child OK!\n");
wait(NULL);
}
}
编译运行结果:

2、管道实现父子进程间同步实例:
/* pipe_sync.c */
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSIZE 1024 int fd1[2], fd2[2];
char c; void tell_wait()
{
if(pipe(fd1) < 0 || pipe(fd2) < 0)
{
perror("pipe error");
exit(1);
}
} void tell_parent()
{
if(write(fd1[1], "c", 1) != 1)
{
perror("write error");
exit(1);
}
}
void wait_parent()
{
if(read(fd2[0], &c, 1) != 1)
{
perror("read error");
exit(1);
}
if(c != 'p')
{
printf("wait_parent: invalid data\n");
exit(1);
}
}
void tell_child()
{
if(write(fd2[1], "p", 1) != 1)
{
perror("write error");
exit(1);
}
}
void wait_child()
{
if(read(fd1[0], &c, 1) != 1)
{
perror("read error");
exit(1);
}
if(c != 'c')
{
printf("wait_child: invalid data");
exit(1);
}
} int
main(void)
{
int pid;
tell_wait();
if((pid = fork()) < 0)
{
perror("fork error");
exit(1);
}
else if(pid == 0)
{
printf("child: first\n");
tell_parent();
}
else
{
wait_child();
printf("parent: after child\n");
}
return(0);
}
编译运行结果:

二、命名管道(FIFO)

在文件系统中命名管道是以设备特殊文件的形式存在的。
不同的进程可以通过命名管道共享数据。
关于FIFO详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3561632.html。
FIFO实现进程间通信实例:
/***************************
* **** FIFO server**********
***************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #define FIFO "/home/zhu/network/fifo/myfifo"
#define OPEN_MODE O_RDONLY int
main(void)
{
int fifofd;
char buf[80];
unlink(FIFO); /* 防止FIFO已存在 */
if(mkfifo(FIFO, 0777) == -1)
{
perror("mkfifo");
exit(1);
} if((fifofd = open(FIFO, OPEN_MODE)) < 0)
{
perror("open");
exit(1);
} read(fifofd, buf, sizeof(buf));
printf("message from client: %s\n", buf); close(fifofd); return(0);
}
/***************************
* **** FIFO client**********
***************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #define FIFO "/home/zhu/network/fifo/myfifo"
#define OPEN_MODE O_WRONLY
int
main(void)
{
int fifofd;
char s[] = "hello,server!"; if((fifofd = open(FIFO, OPEN_MODE)) < 0)
{
perror("open");
exit(1);
} write(fifofd, s, sizeof(s));
printf("write message: %s\n", s); close(fifofd); return(0);
}
编译成功后,我们首先运行服务器(创建FIFO,等待客户发来消息,此时FIFO服务器阻塞):

接着我们在另一个终端窗口运行客户程序,如下图所示,可以看出客户端已成功发送,服务器端也成功接收:

三、消息队列
消息队列是内核地址空间中的内部链表,通过Linux内核在各个进程之间传递内容。
关于消息队列详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3561820.html。
消息队列实现进程间通信实例:
/***************************
*******MSGQ server**********
***************************/
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> #define msqpath "/home/zhu/network/msgqueue/msq"
#define proj_id 'b' struct mymesg {
long mtype;
char mtext[512];
}; int
main(void)
{
key_t key;
int msqid;
struct msqid_ds buf;
struct mymesg msg1;
msg1.mtype = 1;
sprintf(msg1.mtext, "hello"); if((key = ftok(msqpath, proj_id)) < 0)
{
perror("ftok");
exit(1);
} if((msqid = msgget(key, IPC_CREAT)) < 0)
{
perror("msgget");
exit(1);
} if(msgsnd(msqid, &msg1, sizeof(msg1), IPC_NOWAIT) < 0)
{
perror("msgsnd");
exit(1);
}
printf(“send message : hello\n”);
if(msgctl(msqid, IPC_STAT, &buf) < 0)
{
perror("msgctl");
exit(1);
}
printf("message queue # of messages is: %d\n", buf.msg_qnum);
return(0); }
/*****************************
**********MSGQ client*********
*****************************/
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> #define msqpath "/home/zhu/network/msgqueue/msq"
#define proj_id 'b' struct mymesg {
long mtype;
char mtext[512];
}; int
main(void)
{
key_t key;
int msqid;
struct msqid_ds buf;
struct mymesg msg1; if((key = ftok(msqpath, proj_id)) < 0)
{
perror("ftok");
exit(1);
} if((msqid = msgget(key, IPC_EXCL)) < 0)
{
perror("msgget");
exit(1);
} if(msgrcv(msqid, &msg1, sizeof(msg1), 0, IPC_NOWAIT) < 0)
{
perror("msgrcv");
exit(1);
}
printf("receive message : %s\n", msg1.mtext); if(msgctl(msqid, IPC_STAT, &buf) < 0)
{
perror("msgctl");
exit(1);
}
printf("message queue # of messages is: %d\n", buf.msg_qnum);
return(0); }
编译后运行结果如下:

四、信号量
信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。它们常常被用作一个锁机制,在某个进程正在对特定资源进行访问时,信号量可以防止另一个进程去访问它。
关于信号量详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3562046.html。
信号量实现资源控制实例:
#include <sys/types.h>
#include <linux/sem.h>
#include <linux/ipc.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> #define sempath "/home/zhu/network/semaphore/sem"
#define proj_id 'c' int
main(void)
{
int semid, i;
key_t key;
union semun sem, getsem;
sem.val = 3; if((key = ftok(sempath, proj_id)) < 0)
{
perror("ftok");
exit(1);
} if((semid = semget(key, 1, IPC_CREAT)) < 0)
{
perror("semget");
exit(1);
} semctl(semid, 0, SETVAL, sem); semctl(semid, 0, GETVAL, sem);
printf("# of usable semphore: %d\n", sem.val); struct sembuf sops = {0, -1, IPC_NOWAIT};
for(i = 0; i < 4; i++)
{
printf(“%dth:”,i+1);
fflush(stdout);
if(semop(semid, &sops, 1) < 0)
{
perror("semop");
exit(1);
}
printf("ask for one semaphore:success!\n");
}
return(0);
}
编译运行结果如下(因为我们把信号量值设置为3,所以第四次资源请求失败):

注意,在上面的程序中,包含的头文件#include <linux/sem.h> 和#include <linux/ipc.h>。而不是#include <sys/sem.h> #include <sys/ipc.h>。否则出现“storage of size of 'sem' isn't know”的错误。详细介绍请参考http://hi.baidu.com/yuhongyangcn/item/f52545b33c1b55a1eaba93ac。
关于POSIX信号量详情可参考http://www.cnblogs.com/nufangrensheng/p/3564306.html。
注意使用POSIX信号量时,除了要包含头文件<semaphore.h>外,在编译选项中还有加上-lrt选项,否则出现“undefined reference to”这样的编译错误。
五、共享内存
共享内存是在多个进程之间共享内存区域的一种进程间通信的方式,它是在多个进程间对内存段进行映射的方式实现内存共享的。这是最快的IPC方式。
关于共享内存详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3563712.html。
共享内存实现父子进程间通信(这里为了简化、突出共享内存的使用方式,并没有加入同步处理,而只是简单地使用sleep模拟同步):
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h> static char msg[] = "hello, share memory!"; int
main(void)
{
key_t key;
char i, *shms, *shmc;
pid_t pid;
int shmid; key = ftok("/home/zhu/network/shmm/shm", 'a'); shmid = shmget(key, 1024, IPC_CREAT | 0604); pid = fork();
if( pid > 0)
{
shms = (char *)shmat(shmid, 0, 0);
memcpy(shms, msg, strlen(msg) + 1);
sleep(5); shmdt(shms);
}
else if(pid == 0)
{
shmc = (char *)shmat(shmid, 0, 0);
sleep(2);
printf("the content in the share memory is : %s\n", shmc);
shmdt(shmc);
} return(0);
}
运行结果:

六、信号
信号(signal)机制是UNIX系统中最为古老的进程之间的通信机制。它用于在一个或多个进程之间传递异步信号。
关于信号详细介绍可参考http://www.cnblogs.com/nufangrensheng/p/3514157.html。
进程间通信和同步:pipe、FIFO、消息队列、信号量、共享内存、信号的更多相关文章
- Linux进程间通信(消息队列/信号量+共享内存)
写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...
- 进程间通信之信号量、消息队列、共享内存(system v的shm和mmap)+信号signal
进程间通信方式有:System v unix提供3种进程间通信IPC:信号量.消息队列.共享内存.此外,传统方法:信号.管道.socket套接字. [注意上述6种方式只能用户层进程间通信.内核内部有类 ...
- 8.7 进程间的通讯:管道、消息队列、共享内存、信号量、信号、Socket
进程间的通讯 进程间为什么需要通讯? 共享数据.数据传输.消息通知.进程控制 进程间的通讯有哪些类型? 首先,联系前面讲过的知识,进程之间的用户地址空间是相互独立的,不能进行互相访问,但是,内核空间却 ...
- boost进程间通信经常使用开发一篇全(消息队列,共享内存,信号)
本文概要: 敏捷开发大家想必知道并且评价甚高,缩短开发周期,提高开发质量.将大project独立为不同的小app开发,整个开发过程,程序可用可測,所以提高了总体的质量.基于这样的开发模式和开发理念,进 ...
- 四十九、进程间通信——System V IPC 之消息队列
49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...
- Linux进程间通信(七):消息队列 msgget()、msgsend()、msgrcv()、msgctl()
下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信 -- 使用命名管道 一.什么是消息队列 消息队列提 ...
- c/c++ linux 进程间通信系列6,使用消息队列(message queue)
linux 进程间通信系列6,使用消息队列(message queue) 概念:消息排队,先进先出(FIFO),消息一旦出队,就从队列里消失了. 1,创建消息队列(message queue) 2,写 ...
- Linux进程间通信IPC学习笔记之消息队列(SVR4)
Linux进程间通信IPC学习笔记之消息队列(SVR4)
- PHP进程通信基础——信号量+共享内存通信
PHP进程通信基础--信号量+共享内存通信 由于进程之间谁先执行并不确定,这取决于内核的进程调度算法,其中比较复杂.由此有可能多进程在相同的时间内同时访问共享内存,从而造成不可预料的错误.信号量这个名 ...
- μC/OS-II 任务的同步与通信 --- 消息队列
简介 使用消息队列可以在任务之间传递多条消息.消息队列由三个部分组成:事件控制块.消息队列和消息. 当把事件控制块成员 OSEventType 的值置为 OS_EVENT_TYPE_Q 时,该事件控制 ...
随机推荐
- 第一个自定义HTML网页
前言 已经好几天没玩LOL了,实在手痒,下载了游戏,又卸载了,坦言:毛爷爷说的”好好天天向上“,真不容易.但还是回到学习个状态了,开始写,就“根本停不下来”,我也慢慢感受到代码的快乐了,并且想总结出一 ...
- 开源框架DNN简介以及安装
donetnuke 是一款免费的开源cms框架,目前也有收费版,不过免费版也可以适应大家大部分的需求.我前些阵子是老板让我在20天内,做好一个官网并且发布,并且指定使用dnn这个框架,考虑到又可以学习 ...
- MySQL Connector_J_5.1.34_2014.10
5.1版本符合JDBC3.0和JDBC4.0规范 跟MySQL4.1-5.7兼容 5.1.21以后支持JDK7的JDBC4.1规范 在MySQL4.1之前,是不支持utf8的 com.mysql.jd ...
- 实体框架 (EF) 入门 => 四、CodeFirst 枚举支持
当使用 Code First 开发时,通常是从编写用来定义概念(域)模型的 .NET Framework 类开始. 插入记录没有为 Budget 赋值. 数值类型默认值为0,数据库中都为not nul ...
- POJ 3347 Kadj Squares
Kadj Squares Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 2132 Accepted: 843 Descr ...
- ESB后台error日志
本地tomcat没异常 开发环境,生产环境 ESB使用axis2.jar 后台会有错误,但不影响所有流程,该错误源自common.log的error,在捕捉异常后,并未往外继续抛 [ESB 打印] 接 ...
- Linux查看系统信息命令总结
系统 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/cpuinf ...
- JS初识(着重讲解Date函数)
查看类型:typeof() 转换为int类型:parseInt() isNaN() 函数用于检查其参数是否是非数字值. NaN,是Not a Number的缩写.一种计算机用语.NaN 用于处理计算中 ...
- emWin(ucGui)的Edit控件退格处理方法 worldsing
在enWin(ucGui)中EDIT控件在数值模式(十进制/十六进制/二进制/浮点数)下编辑是,无法使用BackSpace键进行退格,主要涉及到的函数有: EDIT_SetBinMode() EDIT ...
- 欧几里德&扩展以及求解线性方程学习总结--附上poj1061解题报告
欧几里德算法: 欧几里德就是辗转相除法,调用这个gcd(a,b)这个函数求解a,b的最大公约数 公式: gcd(a,b)=gcd(b,a%b):并且gcd(a,b)=gcd(b,a)=gcd(-a,b ...