关于进程间通信的总结(IPC)
一:三个问题
进程间通信简单的说有三个问题。第一个问题是一个进程如何把信息传递给另一个。第二个要处理的问题是是,要确保两个或更多的的进程在关键互动中不会出现交叉(即是进程互斥的问题),第三个问题是与正确的顺序有关(即是进程之间的同步问题)。
二:信号量及PV操作
解决互斥进入临界区分为两种解决方案,软件解决方案和硬件解决方案,软件解决方案有Peterson解法,硬件解决方案有TSL指令, XCHG指令等。上述的解决方案都有忙等待的缺点,并且主要是用来解决互斥问题。
信号量是一种解决进程同步的解决方案,同时信号量也可以当作互斥量来使用。使用信号量来解决进程同步问题也是编程中使用较多的方法。使用信号量解决进程同步比较经典的问题是生产者消费者问题。Linux代码演示如下。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h> #define N 5 // 消费者或者生产者的数目
#define M 10 // 缓冲数目
//int M=10;
int in = 0; // 生产者放置产品的位置
int out = 0; // 消费者取产品的位置 int buff[M] = { 0 }; // 缓冲初始化为0,开始时没有产品 sem_t empty_sem; // 同步信号量,当满了时阻止生产者放产品
sem_t full_sem; // 同步信号量,当没产品时阻止消费者消费
pthread_mutex_t mutex; // 互斥信号量,一次只有一个线程访问缓冲 int product_id = 0; //生产者id
int prochase_id = 0; //消费者id
//信号处理函数
void Handlesignal(int signo){
printf("程序退出%d\n",signo);
exit(0);
}
/* 打印缓冲情况 */
void print() {
int i;
printf("产品队列为");
for(i = 0; i < M; i++)
printf("%d", buff[i]);
printf("\n");
} /* 生产者方法 */
void *product() {
int id = ++product_id;
while(1) {//重复进行
//用sleep的数量可以调节生产和消费的速度,便于观察
sleep(2); sem_wait(&empty_sem);
pthread_mutex_lock(&mutex); in= in % M;
printf("生产者%d在产品队列中放入第%d个产品\t",id, in); buff[in]= 1;
print();
++in; pthread_mutex_unlock(&mutex);
sem_post(&full_sem);
}
} /* 消费者方法 */
void *prochase() {
int id = ++prochase_id;
while(1) {//重复进行
//用sleep的数量可以调节生产和消费的速度,便于观察
sleep(5); sem_wait(&full_sem);
pthread_mutex_lock(&mutex); out= out % M;
printf("消费者%d从产品队列中取出第%d个产品\t",id, out); buff[out]= 0;
print();
++out; pthread_mutex_unlock(&mutex);
sem_post(&empty_sem);
}
} int main() {
printf("生产者和消费者数目都为5,产品缓冲为10,生产者每2秒生产一个产品,消费者每5秒消费一个产品,Ctrl+退出程序\n");
pthread_t id1[N];
pthread_t id2[N];
int i;
int ret[N];
//结束程序
if(signal(SIGINT,Handlesignal)==SIG_ERR){//按ctrl+C产生SIGINT信号
printf("信号安装出错\n");
}
// 初始化同步信号量
int ini1 = sem_init(&empty_sem, 0, M);//产品队列缓冲同步
int ini2 = sem_init(&full_sem, 0, 0);//线程运行同步
if(ini1 && ini2 != 0) {
printf("信号量初始化失败!\n");
exit(1);
}
//初始化互斥信号量
int ini3 = pthread_mutex_init(&mutex, NULL);
if(ini3 != 0) {
printf("线程同步初始化失败!\n");
exit(1);
}
// 创建N个生产者线程
for(i = 0; i < N; i++) {
ret[i]= pthread_create(&id1[i], NULL, product, (void *) (&i));
if(ret[i] != 0) {
printf("生产者%d线程创建失败!\n", i);
exit(1);
}
}
//创建N个消费者线程
for(i = 0; i < N; i++) {
ret[i]= pthread_create(&id2[i], NULL, prochase, NULL);
if(ret[i] != 0) {
printf("消费者%d线程创建失败!\n", i);
exit(1);
}
}
//等待线程销毁
for(i = 0; i < N; i++) {
pthread_join(id1[i], NULL);
pthread_join(id2[i],NULL);
}
exit(0);
}
在线程中也可以使用条件量解决生产者消费者问题,具体代码演示参考我的另一篇博客使用条件量解决生产者消费者问题。
三:管程
为了更易于编写正确的程序,Brinch Hansen (1973)和Hoare(1974)提出了一种高级同步原语,称为管程(monitor)。在下面的介绍中我们会发现,他们两人提出的方案略有不同。一个管程是一个由过程、变量及数据结构等组成的一个集合,它们组成一个特殊的模块或软件包。进程可在任何需要的时候调用管程中的过程,但它们不能在管程之外声明的过程中直接访问管程内的数据结构。C、C++不支持管程,Java语言支持管程。
四:其他通信方式
与管程和信号量有关的另一个问题是是,这些机制否是设计用来解决访问公共内存的一个或多个CPU上的互斥问题的。通过将信号量放在共享内存并用TSL或XCHG指令来保护他们,可以避免竞争。如果一个分布式系统具有多个CPU,并且每个CPU拥有自己的私有内存,他们通过一个局域网相连,那么这些源于将失效。这里的结论是信号量太低级,而管程在少数几个编程语言之外又无法使用,并且,这些源于均未提供机器见信息的交换方法。所以还需要其他办法。
1.消息传递
2.屏障
关于进程间通信的总结(IPC)的更多相关文章
- 四十九、进程间通信——System V IPC 之消息队列
49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...
- linux 进程间通信机制(IPC机制)一总览
1.作用:进程间通信机制(Inter Process Communication,IPC),这些IPC机制的存在使UNIX在进程通信领域手段相当丰富,也使得程序员在开发一个由多个进程协作的任务组成的系 ...
- 进程间通信之XSI IPC
XSI IPC源自于系统V的IPC功能. 有三种IPC我们称作XSI IPC,即消息队列.信号量以及共享存储器,它们之间有很多相似之处. 1.标识符和键 每个内核中的IPC结构(消息队列.信号量或共享 ...
- 五十、进程间通信——System V IPC 之共享内存
50.1 共享内存 50.1.1 共享内存的概念 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到自己的虚拟内存空间.所有用户空间的进程若要操作共享内存,都要将其映射到自己 ...
- linux 进程间通信机制(IPC机制)一消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息 ...
- 五十一、进程间通信——System V IPC 之进程信号量
51.1 进程信号量 51.1.1 信号量 本质上就是共享资源的数目,用来控制对共享资源的访问 用于进程间的互斥和同步 每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可对所有信 ...
- linux 进程间通信机制(IPC机制)- 管道
一,定义: 管道又可以分为无名管道和命名管道,两者的用途是不一样的. 无名管道PIPE:主要用于具有亲缘关系的进程之间的通信,无名管道的通信是单向的,只能由一段到另外一段:无名管道是临时性的,完成通信 ...
- 【IPC第二个进程间通信】管道Pipe
IPC进程间通信+管道Pipe IPC(Inter-Process Communication,进程间通信). 管道用于进程间共享数据,事实上质是共享内存 ...
- 进程间通信 IPC(Inter-Process Communication)
目录 一.管道 二.FIFO 三.消息队列 四.信号量 五.共享存储 六.网络IPC:套接字 一.管道 管道是进程间通信中最古老的方式,所有UNIX都提供此种通信机制.管道有以下两种局限性: 历史 ...
- Windows下进程间通信及数据共享
进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码.数据以及它可利用的系统资源(如文件.管道等)组成. 多进程/多线程是Windows操作系统的一个基本特征.Microsoft W ...
随机推荐
- ural 1993 This cheeseburger you don't need
顺次存到{} [] () 遇到逗号就处理下,最后处理逗号之后的 #include <iostream> #include <cstring> #include <stri ...
- iOS开发——语法篇OC篇&静态方法与实例方法
静态方法与实例方法 方法是类的行为,写在接口和实现两个文件中.在接口部分声明方法,在实现部分实现方法. 1.类方法与实例方法 Objective-C中的类可以声明两种类型的方法:实例方法和类方法.实例 ...
- 使用命令xrandr设置当前系统的显示分辨率及显示的旋转脚本
/********************************************************************* * Author : Samson * Date ...
- xtrabackup原理1
http://www.cnblogs.com/Amaranthus/archive/2014/08/19/3922570.html Percona XtraBackup User Manual 阅读笔 ...
- Python学习 之 编程
1.搭建python环境 交互模式:输入python进入交互模式,exit()退出交互模式 文本模式:新建*.py文件,编辑*.py文件,运行python *.py 2.python文件类型 (1)源 ...
- 实例源码--Android简单音乐播放器源码
下载源码 技术要点: 1.本地音乐管理 2.在线音乐听歌.下载 3.音频流的解码 4. HTTP通信模块 5. Sqlite数据库 6. 源码带详细的中文注释 ...... 详细介绍: 1.本 ...
- C语言第五节scanf函数
变量的内存分析 字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的"字节"和"地址". 内存以"字节为单位" 0x表示的 ...
- Android(java)学习笔记82:我们到底该如何处理异常?
我们到底该如何处理异常? 原则: 如果该功能内部可以将问题处理,用try,自己能解决就自己解决问题. 如果处理不了,交由调用者处理,这是用throws,自己不能解决的问题,我们就抛出去交个调用者解决这 ...
- [课程相关]homework-08
一.变量作用域和生命周期 #include <cstdlib> #include <iostream> using namespace std; void try_change ...
- TensorFlow安装与测试
官网:http://tensorflow.org/安装步骤:1.sudo apt-get install python-pip python-dev python-virtualenv 2.virtu ...