精华内容
下载资源
问答
  • ipcs命令是用于报告Linux中进程间通信设施的状态,显示的信息包括消息列表、共享内存和信号量的信息 。 语法格式:ipcs [参数] 常用参数: -a 默认的输出信息 -m 打印出使用共享内存进行进程间通信的信息 -q ...
  • linux进程--进程间通信方式(一)

    千次阅读 2020-06-04 17:32:39
    将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程进程id。 对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;...

    一、多进程

    首先,先来讲一下fork之后,发生了什么事情。

    由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。 对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id。(进程id 0总是由交换进程使用,所以一个子进程的进程id不可能为0 )。

    fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。

    可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们分别作不同的工作,也就是分岔了。这也是fork为什么叫fork的原因

    至于那一个最先运行,可能与操作系统(调度算法)有关,而且这个问题在实际应用中并不重要,如果需要父子进程协同,可以通过原语的办法解决。

    二、常见的通信方式

    1. 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
    2. 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
    3. 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    4. 共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
    5. 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
    6. 套接字Socket:套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
    7. 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

    三、信号

    信号是Linux系统中用于进程之间通信或操作的一种机制,信号可以在任何时候发送给某一进程,而无须知道该进程的状态。如果该进程并未处于执行状态,则该信号就由内核保存起来,知道该进程恢复执行并传递给他为止。如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

    Linux提供了几十种信号,分别代表着不同的意义。信号之间依靠他们的值来区分,但是通常在程序中使用信号的名字来表示一个信号。在Linux系统中,这些信号和以他们的名称命名的常量被定义在/usr/includebitssignum.h文件中。通常程序中直接包含<signal.h>就好。

    信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式,信号可以在用户空间进程和内核之间直接交互。内核也可以利用信号来通知用户空间的进程来通知用户空间发生了哪些系统事件。信号事件有两个来源:

    • 硬件来源,例如按下了cltr+C,通常产生中断信号sigint
    • 软件来源,例如使用系统调用或者命令发出信号。最常用的发送信号的系统函数是kill,raise,setitimer,sigation,sigqueue函数。软件来源还包括一些非法运算等操作。

    一旦有信号产生,用户进程对信号产生的相应有三种方式:

    • 执行默认操作,linux对每种信号都规定了默认操作。
    • 捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数。
    • 忽略信号,当不希望接收到的信号对进程的执行产生影响,而让进程继续执行时,可以忽略该信号,即不对信号进程作任何处理。

    有两个信号是应用进程无法捕捉和忽略的,即SIGKILL和SIGSTOP,这是为了使系统管理员能在任何时候中断或结束某一特定的进程。
    在这里插入图片描述
    在这里插入图片描述
    上图表示了Linux中常见的命令

    1、信号发送

    信号发送的关键使得系统知道向哪个进程发送信号以及发送什么信号。下面是信号操作中常用的函数:
    在这里插入图片描述
    例子:创建子进程,为了使子进程不在父进程发出信号前结束,子进程中使用raise函数发送sigstop信号,使自己暂停;父进程使用信号操作的kill函数,向子进程发送sigkill信号,子进程收到此信号,结束子进程。
    在这里插入图片描述

    2、信号处理

    当某个信号被发送到一个正在运行的进程时,该进程即对次特定的信号注册相应的信号处理函数,以完成所需处理。设置信号处理方式的是signal函数,在程序正常结束前,在应用signal函数恢复系统对信号的默认处理方式。
    在这里插入图片描述

    3、信号阻塞

    有时候既不希望进程在接收到信号时立刻中断进程的执行,也不希望此信号完全被忽略掉,而是希望延迟一段时间再去调用信号处理函数,这个时候就需要信号阻塞来完成。
    在这里插入图片描述
    例子:主程序阻塞了cltr+c的sigint信号。用sigpromask将sigint假如阻塞信号集合。
    在这里插入图片描述

    四、管道

    管道允许在进程之间按先进先出的方式传送数据,是进程间通信的一种常见方式。

    管道是Linux 支持的最初Unix IPC形式之一,具有以下特点:

    1. 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
    2. 匿名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
    3. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

    管道分为pipe(无名管道)和fifo(命名管道)两种,除了建立、打开、删除的方式不同外,这两种管道几乎是一样的。他们都是通过内核缓冲区实现数据传输。

    • pipe用于相关进程之间的通信,例如父进程和子进程,它通过pipe()系统调用来创建并打开,当最后一个使用它的进程关闭对他的引用时,pipe将自动撤销。
    • FIFO即命名管道,在磁盘上有对应的节点,但没有数据块——换言之,只是拥有一个名字和相应的访问权限,通过mknode()系统调用或者mkfifo()函数来建立的。一旦建立,任何进程都可以通过文件名将其打开和进行读写,而不局限于父子进程,当然前提是进程对FIFO有适当的访问权。当不再被进程使用时,FIFO在内存中释放,但磁盘节点仍然存在。

    管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺序地读取数据,该缓冲区可以看做一个循环队列,读和写的位置都是自动增加的,一个数据只能被读一次,读出以后再缓冲区都不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或写进程是否进入等待队列,当空的缓冲区有新数据写入或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。
    在这里插入图片描述

    1、无名管道

    pipe的例子:父进程创建管道,并在管道中写入数据,而子进程从管道读出数据
    在这里插入图片描述

    2、命名管道

    和无名管道的主要区别在于,命名管道有一个名字,命名管道的名字对应于一个磁盘索引节点,有了这个文件名,任何进程有相应的权限都可以对它进行访问。

    而无名管道却不同,进程只能访问自己或祖先创建的管道,而不能访任意访问已经存在的管道——因为没有名字。

    Linux中通过系统调用mknod()或makefifo()来创建一个命名管道。最简单的方式是通过直接使用shell

    mkfifo myfifo
    

    等价于

    mknod myfifo p
    

    以上命令在当前目录下创建了一个名为myfifo的命名管道。用ls -p命令查看文件的类型时,可以看到命名管道对应的文件名后有一条竖线"|",表示该文件不是普通文件而是命名管道。

    使用open()函数通过文件名可以打开已经创建的命名管道,而无名管道不能由open来打开。当一个命名管道不再被任何进程打开时,它没有消失,还可以再次被打开,就像打开一个磁盘文件一样。

    可以用删除普通文件的方法将其删除,实际删除的事磁盘上对应的节点信息。

    例子:用命名管道实现聊天程序,一个张三端,一个李四端。两个程序都建立两个命名管道,fifo1,fifo2,张三写fifo1,李四读fifo1;李四写fifo2,张三读fifo2。

    用select把,管道描述符和stdin假如集合,用select进行阻塞,如果有i/o的时候唤醒进程。(粉红色部分为select部分,黄色部分为命名管道部分)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在linux系统中,除了用pipe系统调用建立管道外,还可以使用C函数库中管道函数popen函数来建立管道,使用pclose关闭管道。

    例子:设计一个程序用popen创建管道,实现 ls -l |grep main.c的功能

    分析:先用popen函数创建一个读管道,调用fread函数将ls -l的结果存入buf变量,用printf函数输出内容,用pclose关闭读管道;

    接着用popen函数创建一个写管道,调用fprintf函数将buf的内容写入管道,运行grep命令。
    在这里插入图片描述
    popen的函数原型:

    FILE* popen(const char* command,const char* type);
    

    参数说明:command是子进程要执行的命令,type表示管道的类型,r表示读管道,w代表写管道。如果成功返回管道文件的指针,否则返回NULL。

    使用popen函数读写管道,实际上也是调用pipe函数调用建立一个管道,再调用fork函数建立子进程,接着会建立一个shell 环境,并在这个shell环境中执行参数所指定的进程。

    五、消息队列

    消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。

    消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。

    可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

    消息队列的常用函数如下表:
    在这里插入图片描述
    进程间通过消息队列通信,主要是:创建或打开消息队列,添加消息,读取消息和控制消息队列。

    例子:用函数msget创建消息队列,调用msgsnd函数,把输入的字符串添加到消息队列中,然后调用msgrcv函数,读取消息队列中的消息并打印输出,最后再调用msgctl函数,删除系统内核中的消息队列。(黄色部分是消息队列相关的关键代码,粉色部分是读取stdin的关键代码)
    在这里插入图片描述

    六、共享内存

    共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。

    采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队里等通信方式,则需要再内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。
    在这里插入图片描述
    一般而言,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时在重新建立共享内存区域;而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件,因此,采用共享内存的通信方式效率非常高。
    在这里插入图片描述
    共享内存有两种实现方式:1、内存映射 2、共享内存机制

    1、内存映射

    内存映射 memory map机制使进程之间通过映射同一个普通文件实现共享内存,通过mmap()系统调用实现。普通文件被映射到进程地址空间后,进程可以

    像访问普通内存一样对文件进行访问,不必再调用read/write等文件操作函数。

    例子:创建子进程,父子进程通过匿名映射实现共享内存。

    分析:主程序中先调用mmap映射内存,然后再调用fork函数创建进程。那么在调用fork函数之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap函数的返回地址,这样,父子进程就可以通过映射区域进行通信了。
    在这里插入图片描述

    2、UNIX System V共享内存机制

    IPC的共享内存指的是把所有的共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。

    和前面的mmap系统调用通过映射一个普通文件实现共享内存不同,UNIX system V共享内存是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信。

    例子:设计两个程序,通过unix system v共享内存机制,一个程序写入共享区域,另一个程序读取共享区域。

    分析:一个程序调用fotk函数产生标准的key,接着调用shmget函数,获取共享内存区域的id,调用shmat函数,映射内存,循环计算年龄,另一个程序读取共享内存。

    (fotk函数在消息队列部分已经用过了,根据pathname指定的文件(或目录)名称,以及proj参数指定的数字,ftok函数为IPC对象生成一个唯一性的键值。)

    key_t ftok(char* pathname,char proj)
    

    在这里插入图片描述

    原文链接:https://www.cnblogs.com/luo77/p/5816326.html

    展开全文
  • 一、进程间通信(IPC,Inter-Process Communication)是指在不同进程间传播或交换信息 1. 无名管道 特点 半双工(数据流向仅有一个方向),具有固定的读端和写端 只能用于父进程或兄弟线程之间通信(具有血缘关系的...

    一、进程间通信(IPC,Inter-Process Communication)是指在不同进程间传播或交换信息

    1. 无名管道

    特点

    • 半双工(数据流向仅有一个方向),具有固定的读端和写端
    • 只能用于父进程或兄弟线程之间通信(具有血缘关系的线程之间)
    • 一种特殊文件,可以用普通的read、write函数进行读写,但又不是普通文件,不属于任何其它文件系统,仅存在于内存之中
    • 通信的数据是无格式的流并且大小受限

    2. 命名管道(先进先出队列)

    特点

    不同于无名管道之处在于它提供一个与之关联的路径名,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,不相关的进程也能通过FIFO交换数据

    FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。如图

    3. 消息队列

    • 消息队列,是消息的链接表,存放在内核中。其中的消息具有特定的格式以及特定的优先级
    • 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
    • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取

    4. 信号量

    信号量(semaphore)是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

    5. 共享内存

    现代操作系统,对于内存管理,采用的是虚拟内存技术,也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程 A 和 进程 B 的虚拟地址是一样的,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。但是,如果两个进程通过页表将虚拟地址映射到物理地址时,有一部分物理内存重合了,那么这部分重合的内存就是即共享内存,它可以被两个进程同时看到。在共享内存中,一个进程进行写操作,另一个进程进行读操作,这样它们就可以实现进程间通信。但是,我们要确保一个进程在写的时候不能被读,因此我们使用信号量来实现同步与互斥。

     

     

    • 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取
    • 因为多个进程可能会同时操作共享的内存,所以需要进行同步
    • 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问

    6. 套接字(socket)

    与其他进程通信方式不同,它可用于不同机器间的进程通信

    二、Linux线程间通信

    操作系统中线程间的通信有两种情况:

    1. 不同进程的线程之间进行通信,由于两个线程只能访问自己所属进程的地址空间和资源,故等同于进程间的通信。(上面已经介绍了)
    2. 同一个进程中的两个线程进行通信。

    由于同一进程中的线程之间有共享内存,因此它们之间的通信是通过共享内存实现的。

    三、Java线程间通信

    从根本上来说,线程间的通信有两种方式:

    • 一种是在共享内存的并发模型中,线程之间通过读-写共享内存来实现通信(公共状态)
    • 一种是在消息传递的并发模型里,线程之间通过发送消息来进行通信(没有公共状态)

    而Java的并发采用的是共享内存模型,所以Java线程之间的通信是基于共享内存实现的。具体来讲Java线程之间的通信由Java内存模型控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。如果线程A与B之间要通信的话,必须经历下面两个步骤:

    1. 线程A把本地内存中更新过的共享变量刷新到主内存中去。
    2. 线程B到住内存中去读取线程A之前更新过的共享变量。(如图)

    现在问题来了,假设共享内存中的共享变量a,如果多个线程同时读a,不会出现任何问题,但是如果这些线程中有至少一个线程对a执行写操作,就可能出现数据不一致问题,也就是线程不安全了,那这是绝对不允许的。怎么办?答案就是依靠线程同步,来保证即使多个线程并发访问共享变量时,依然能够保证数据一致!

    所以,就出现了个各种各样的锁呀,并发工具包呀

    1. volatile

    2. java中的wait()/notify()/notifyAll()

    底层是如何通过并发控制保证基于共享内存的通信的正确性和安全性

    线程间通信的几种实现方式

    线程通信的四种方式

    linux基础——linux线程间通信及同步机制总结

    展开全文
  • 进程间通信的方式有哪些? 1、进程间通讯方式有:管道,信号,信号量,消息队列,共享内存,套接字共六种 2、管道:管道分为有名管道和无名管道,其中无名管道是一种半双工的通信方式,数据只能单向流动,而且...

    进程间通信的方式有哪些?




    1、进程间通讯方式有:管道,信号,信号量,消息队列,共享内存,套接字共六种

    2、管道:管道分为有名管道和无名管道,其中无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,一般用于两个不同进程之间的通信。有名管道也是一种半双工的通信方式,但它允许无亲缘关系进程间的通信。

    3、信号:信号是一种比较复杂的通信方式,信号产生的条件:按键、硬件异常、进程调用kill函数将信号发送给另一个进程、用户调用kill命令将信号发送给其他进程,传递的消息比较少用于通知接收进程某个时间已经发生

    4、信号量:信号量是一个计数器,可以用来控制多个线程对共享资源的访问,它不是用于交换大批数据,而用于多线程之间的同 步。他常作为一种锁机制。因此,主要作为进程间以及同一个进程内不同线程之间的同步手段

    5、消息队列:消息队列是消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了信号传递信息少,管道只能承载 无格式字节流以及缓冲区大小受限等特点。

    6、共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。他往 往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。

    7、套接字:套接字可用于不同及其间的进程通信。

    流式套接字: 提供可靠的,面向连接的通讯流

    数据包套接字: 定义一种无连接的服务,通过相互独立的报文进行传输,是无序的

    原始套接字: 用于新的网络协议的测试


    转载自:https://blog.csdn.net/xiaonan153/article/details/81502245

    展开全文
  • 程序员必须让拥有依赖关系的进程集协调,这样才能达到进程的共同目标。可以使用两种技术来达到协调。...这种技术称做进程间通信(interprocess communication)。第二种技术是同步,当进程间相互具有合作依赖时使用

    http://blog.csdn.net/liuzhanchen1987/article/details/7452910

    程序员必须让拥有依赖关系的进程集协调,这样才能达到进程的共同目标。可以使用两种技术来达到协调。第一种技术在具有通信依赖关系的两个进程间传递信息。这种技术称做进程间通信(interprocess communication)。第二种技术是同步,当进程间相互具有合作依赖时使用。这两种类型的依赖关系可以同时存在。

    一般而言,进程有单独的地址空间。我们可以了解下可执行程序被装载到内存后建立的一系列映射等理解这一点。如此以来意味着如果我们有两个进程(进程A和进程B),那么,在进程A中声明的数据对于进程B是不可用的。而且,进程B看不到进程A中发生的事件,反之亦然。如果进程A和B一起工作来完成某个任务,必须有一个在两个进程间通信信息和时间的方法。我们这里可以去看看基本的进程组件。注意进程有一个文本、数据以及堆栈片断。进程可能也有从自由存储空间中分配的其它内存。进程所占有的数据一般位于数据片断、堆栈片断或进程的动态分配内存中。数据对于其它进程来说是受保护的。为了让一个进程访问另外一个进程的数据,必须最终使用操作系统调用。与之类似,为了让一个进程知道另一个进程中文本片断中发生的事件,必须在进程间建立一种通信方式。这也需要来自操作系统API的帮助。当进程将数据发送到另一进程时,称做IPC(interprocess communication,进程间通信)。下面先列举几种不同类型的进程间通信方式:

    进程间通信                                 描述

    环境变量/文件描述符            子进程接受父进程环境数据的拷贝以及所有文件描述符。父进程可以在它的数据片断或环境中设置一定的变量,同时子进程接收这些值。父进程可以打开文件,同时推进读/写指针的位置,而且子进程使用相同的偏移访问该文件。

    命令行参数                      在调用exec或派生函数期间,命令行参数可以传递给子进程。

    管道                            用于相关和无关进程间的通信,而且形成两个进程间的一个通信通道,通常使用文件读写程序访问。

    共享内存                        两个进程之外的内存块,两个进程均可以访问它。

    DDE(动态数据交换,Dynamic data exchange)     使用客户机/服务器模型(C/S),服务器对客户的数据     或动作请求作出反应。

    一、环境变量、文件描述符:

    当创建一个子进程时,它接受了父进程许多资源的拷贝。子进程接受了父进程的文本、堆栈

    以及数据片断的拷贝。子进程也接受了父进程的环境数据以及所有文件描述符的拷贝。子进

    程从父进程继承资源的过程创造了进程间通信的一个机会。父进程可以在它的数据片断或环

    境中设置一定的变量,子进程于是接受这些值。同样,父进程也可以打开一个文件,推进到

    文件内的期望位置,子进程接着就可以在父进程离开读/写指针的准确位置访问该文件。

    这类通信的缺陷在于它是单向的、一次性的通信。也就是说,除了文件描述外,如果子进程

    继承了任何其它数据,也仅仅是父进程拷贝的所有数据。 一旦创建了子进程,由子进程对

    这些变量的任何改变都不会反映到父进程的数据中。同样,创建子进程后,对父进程数据的

    任何改变也不会反映到子进程中。所以,这种类型的进程间通信更像指挥棒传递。一旦父进

    程传递了某些资源的拷贝,子进程对它的使用就是独立的,必须使用原始传递资源。

    二、命令行参数:

    通过命令行参数(command-line argument)可以完成另一种单向、一次性的进程间通信

    我前面的文章已经提到过使用命令行参数。命令行参数在调用一个exec或派生调用操作系

    统时传递给子进程。命令行参数通常在其中一个参数中作为NULL终止字符串传递给exec

    或派生函数调用。这些函数可以按单向、一次性方式给子进程传递值。WINDOWS有调用执行

    exe程序的API。大家可以去参考一下ShellExecuteA函数相关。

    三、管道通信:

    继承资源以及命令行参数是最简单形式的进程间通信。它们同时有两个主要限制。除了文件

    描述符外,继承资源是IPC的单向、一次性形式。传递命令参数也是单向、一次性的IPC

    方法。这些方法也只有限制于关联进程,如果不关联,命令行参数和继承资源不能使用。还

    有另一种结构,称做管道(Pipe),它可以用于在关联进程间以及无关联进程间进行通信。

    管道是一种数据结构,像一个序列化文件一样访问。它形成了两个进程间的一种通信渠道。

    管道结构通过使用文本和写方式来访问。如果进程A希望通过管道发送数据给进程B,那么

    进程A向管道写入数据。为了让进程B接收此数据,进程B必须读取管道,与命令行参数的

    IPC形式不一样。管道可以双向通信。两进程间的数据流是双向通信的。管道可以在程序的

    整个执行期间使用,在进程间发送和接收数据。所以,管道充当可访问管道的进程间的一种

    可活链接,有两种基本管道类型:

    1.  匿名管道

    2.  命名管道

    匿名管道

    上面的图可以看出在没有管道时,两进程是不能互写的。

    匿名管道

    建立管道后就可以相互通信了。

    只有关联进程可以使用匿名管道来通信。无关联进程必须使用命名管道。

    匿名管道:通过文件描述符或文件句柄提供对匿名管道的访问。对系统API的调用创建一个管道,并返回一个文件描述符。这个文件描述符是用作read()或write()函数的一个参数。当通过文件描述符调用read()或write()时,数据的源和目标就是管道。例如,在OS/2环境中使用操作系统函数DosCreatePipe()创建匿名管道:

    int mian( void )

    {

        PFHILE readHandle;

    PFHILE writeHandle;

    DosCreatePipe( readHandle, writeHandle, size );

    }

    在WINDOWS下例如我写的ASM集成环境通过管道与DOS命令行通信的MFC下代码块:

    void CIDEManager::Commond( CString cmd, char* buf, unsigned int bufsize )

    {

        SECURITY_ATTRIBUTES sa;

        HANDLE hRead, hWrite;

        sa.nLength              = sizeof( SECURITY_ATTRIBUTES );

        sa.lpSecurityDescriptor = NULL;

    sa.bInheritHandle       = TRUE;

        if ( !CreatePipe( &hRead, &hWrite, &sa, 0 ) )  // 创建管道

        {

            return;

        }

        STARTUPINFO si;

        PROCESS_INFORMATION pi;

        si.cb = sizeof( STARTUPINFO );

        GetStartupInfo( &si );

        si.hStdError   = hWrite;

        si.hStdOutput  = hWrite;

        si.wShowWindow = SW_HIDE;

        si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    if ( !CreateProcess( NULL, ( LPTSTR )( LPCTSTR )cmd, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi ) )

        {

            return;

        }

        CloseHandle( hWrite );

        DWORD bytesRead;

        while ( TRUE )

        {

            memset( buf, 0, bufsize );

            if ( ReadFile( hRead, buf, bufsize, &bytesRead, NULL ) != NULL )

            {

                break;

            }

            Sleep( 200 );

        }

        CloseHandle( hRead );

        return;

    }

    命名管道:将管道用作两个无关联进程间的通信渠道,程序员必须使用命名管道,它可以看作一种具有某名字的特殊类型文件。进程可以根据它的名字访问这个管道。通过匿名管道,父和子进程可以单独使用文件描述符来访问他们所共享的管道,因为子进程继承了父进程的文件描述符,同时文件描述符用read()或write()函数的参数。因为无关进程不能访问彼此的文件描述符,所以不能使用匿名管道。由于命名管道提供该管道的一个等价文件名,任何知道此管道名字的进程都可以访问它。下面是命名管道相对于匿名管道的优点:

    命名管道可以被无关联进程使用。

    命名管道可以持久。创建它的程序退出后,它们仍然可以存在。

    命名管道可以在网络或分布环境中使用。

    命名管道容易用于多对一关系中。

    与访问匿名管道一样,命名管道也是通过read()或write()函数来访问。两者之间的主要区别在于命名管道的创建方式以及谁可以反问它们。命名管道可以建立一个进程间通信的C/S模型。访问命名管道的进程可能都位于同一台机器上,或位于通过网络通信的不同机器上。由于管道的名字可以通过管道所在服务器的逻辑名,所以能够跨网络访问管道。例如,ServerName//Pipe//MyPipe(不区分大小写)可以作为一个管道名字。假如Server1是网络服务器的名字。当打开或访问这个管道的调用解析文件名时,首先应该定位Server1,然后访问MyPipe。例子如下:

    服务器端:

    int main( void )

    {

        HANDLE pipehandle;

        char buf[ 256 ];

    DWORD bytesRead;

          if( ( pipehandle = CreateNamedPipe( ".//Pipe//cao", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 0, 0, 5000, NULL ) ) == INVALID_HANDLE_VALUE )

        {

            printf( "CreateNamedPipe failed with error %d/n", GetLastError() );

            system( "pause" );

            return 0;

        }

        printf( "server is running/n" ); 

        if( ConnectNamedPipe( pipehandle, NULL ) == 0 )

        {

            printf( "connectNamedPipe failed with error %d/n", GetLastError() );

            CloseHandle( pipehandle );

            system( "pause" );

            return 0;

        }    

        if( ReadFile( pipehandle, buf, sizeof( buf ), &bytesRead, NULL ) == 0 )

        {

            printf( "ReadFile failed with error %d/n", GetLastError() );

            CloseHandle( pipehandle );

            system( "pause" );

            return 0;

        }

        printf( "%s/n", buf );      

        if ( DisconnectNamedPipe( pipehandle ) == 0 )

        {

            printf( "DisconnectNamedPipe failed with error %d/n", GetLastError() );

            CloseHandle( pipehandle );

            system( "pause" );

            return 0;

        }

        system( "pause" );

        return 0;

    }

    客户端:

    int main( void )

    {

        HANDLE pipehandle;

        DWORD writesbytes;

        char buff[ 256 ];

        if( WaitNamedPipe( ".//Pipe//cao", NMPWAIT_WAIT_FOREVER ) == 0 )

        {

            printf( "WaitNamedPipe failed with error %d/n", GetLastError() );

            system( "pause" );

            return 0;

        }

         if( ( pipehandle = CreateFile( ".//Pipe//cao", GENERIC_READ | GENERIC_WRITE, 0, ( LPSECURITY_ATTRIBUTES )NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, ( HANDLE )NULL ) ) == INVALID_HANDLE_VALUE )

        {

            printf( "CreateFile failed with error %d/n", GetLastError() );

            system( "pause" );

            return 0;

        }

        ZeroMemory( &buff, sizeof( buff ) );

        gets( buff );

        if( WriteFile( pipehandle, buff, sizeof( buff ), &writesbytes, NULL ) == 0 )

        {

            printf( "WriteFile failed with error %d/n", GetLastError() );

            CloseHandle( pipehandle );

            system( "pause" );

            return 0;

        }    

        printf( "write %d bytes", writesbytes );

        CloseHandle( pipehandle );

        system( "pause" );

        return 0;

    }

    命名管道不仅可用于无关联进程间、位于不同机器上的两进程间的通信,而且可用于多对一通信,可以建立服务器进程,允许同时通过多个客户访问命名管道。命名管道常常用于多线程服务器。

    四、 共享内存

    共享内存也可以实现进程间的通信。进程需要可以被其他进程浏览的内存块。希望访问这个内存块的其他进程请求对它的访问,或由创建它的进程授予访问内存块的权限。可以访问特定内存块的所有进程对它具有即时可见性。共享内存被映射到使用它的每个进程的地址空间。所以,它看起来像是另一个在进程内声明的变量。当一个进程写共享内存,所有的进程都立即知道写入的内容,而且可以访问。

    进程间共享内存的关系与函数间全局变量的关系相似。程序中的所有函数都可以使用全局变量的值。同样,共享内存块可以被正在执行的所有进程访问。内存块可能共享一个逻辑地址,进程也可以共享某些物理地址。

    共享内存块的创建必须由一个系统API调用来完成。在WIN32环境中,使用CreateFileMapping()、MapViewOfFile()以及MapViewOfFileEx() API能很好地完成。

    共享内存分配位于WIN32系统中2~3GB地址范围内。一旦调用MapViewOfFile()和MapViewOfFileEx(),共享文件映射对象的所有进程都可以立即访问此内存块,而且在需要时,可以读写此内存块。

    五、动态数据交换

    动态数据交换( dynamic data exchange ) 是当今可用的进程间通信最强大和完善的形式之一。动态数据交换使用消息传递、共享内存、事务协议、客户/服务器范畴、同步规则以及会话协议来让数据和控制信息在进程间流动。动态数据交换对话( dynamic data exchange session, DDE )的基本模型是客户、服务器。服务器对来自客户的数据或动作作出反应。客户和服务器可以以多种关系来通信。

    一个服务器可以与任意数量的客户通信。一个客户也可以与任意数量的服务器通信。单个DDE代理既可以是客户,也可以是服务器。也就是说,进程可以从一个正为另一个进程执行服务的DDE代理请求服务。

     

    展开全文
  • 常用进程间通信1 管道(pipe)1.1 匿名管道(pipe)1.2 命名管道(name_pipe)2 信号(signal)3 信号量(semophore)4 共享内存(shared memory)5 消息队列(message queue)6 套接字(socket) 1 管道(pipe) ...
  • Linux下进程间通信的几种主要手段: ...信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持Unix早
  • RPC(Remote Procedure Call)即远程过程调用,它是一种通过网络从远程计算机程序上请求服务,在不需要了解底层网络技术的协议下,即可获取计算机进程中的数据。RPC使得开发包括网络分布式多程序在内的应用程序更加...
  • 进程间通信(IPC,InterProcess Communication):是指在不同进程之间传播或交换信息。 一、简单的进程间通信: 命令行:父进程通过exec函数创建子进程时可以附加一些数据。 环境变量:父进程通过exec函数创建...
  • C#进程间通信方式介绍

    万次阅读 2020-09-29 12:06:06
    进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。 IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持...
  • Unix中的IPC(InterProcess Communication)是各种进程通信的统称,在Unix中有很多线程间通信方法,但是他们并不是兼容Unix的各种实现,下图列出了Linux系统不同实现所支持的不同形式的IPC。 本文将介绍上诉表中...
  • 几种常见进程间通信(IPC)方式-管道pipe 前言 进程间通信是指在不同进程之间传播或交换信息,在Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间,进程之间不能相互访问。必须通过内核才能...
  • 进程间通信方式总结——信号量

    千次阅读 2017-04-14 17:35:50
    Linux/Unix系统IPC是各种进程间通信方式的统称,但是其中极少能在所有Linux/Unix系统实现中进行移植。随着POSIX和Open Group(X/Open)标准化的推进呵护影响的扩大,情况虽已得到改善,但差别仍然存在。一般来说,...
  • Linux进程间通信方式

    万次阅读 多人点赞 2017-10-30 11:09:40
    进程通信的几种方式 管道 管道简介 管道原理 管道如何通信 管道如何创建 管道读写实现 管道api与用法 普通管道 流管道 命名管道 实现原理 api与应用 匿名管道和有名管道总结 信号 信号来源 信号生命周期和...
  • 进程间通信——几种方式的比较和详细实例

    万次阅读 多人点赞 2017-11-14 09:42:47
    1、进程间通信的定义 2、几种通信方式的比较 3、几种通信方式的详细实例 1、进程间通信的定义 进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户...
  • 常见进程间的几种通信方式以及使用注意点 通常情况下进程间通信方式主要有以下几点: 此处只是介绍相关工作过程及概念,具体代码,网上一抓一大片,可以自己看。 1、管道: 管道通常分类两种,一种有名管道,一...
  • 但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获。 二、信号的种类 信号的名称是在头文件signal.h中定义的,信号都以SIG开头,...
  • linux下最快的进程间通信方式共享

    千次阅读 2018-09-19 17:01:09
    问什么说共享内存是最快的进程间通信方式 因为共享内存是直接将一块内存区域映射到虚拟地址空间中,因此在数据通信传输的过程中,相比较其他的通信方式少了将数据从用户态到内核态的数据拷贝过程。 什么意思,就是说...
  • 进程间通信方式总结——消息队列

    千次阅读 2017-04-16 11:52:25
    Linux/Unix系统IPC是各种进程间通信方式的统称,但是其中极少能在所有Linux/Unix系统实现中进行移植。随着POSIX和Open Group(X/Open)标准化的推进呵护影响的扩大,情况虽已得到改善,但差别仍然存在。一般来说,...
  • linux系统进程间通信英文版,里面详细介绍了linux环境下常用进程间通信方式,shared memery, pipes, FIFO, semaphores, message queue, sockets, rpc
  • Python 多进程及进程间通信

    千次阅读 2020-09-03 21:32:33
    作者:billy 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 什么是进程 在了解进程之前,我们需要知道多任务的概念。多任务,顾名思义,就是指操作系统...创建进程常用方式 在 Pyth
  • Android进程间通信(IPC)常用方式

    千次阅读 2016-03-30 17:31:53
    进程间通信方式在Android开发中我们可以通过Intent、ContentProviders来实现进程间通信,如果不限于Android特有的话,我们还可以使用File、Socket等方式,反正只要进程间能交换信息就行了。像Intent,我们平时使用的...
  • linux进程间通信方式及比较

    千次阅读 2014-12-06 17:00:49
    进程间通信方式:  1.管道(pipe)及有名管道(named pipe):  管道可用于具有亲缘关系进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。  2.信号(signal): ...
  • 本文介绍了Android进程间通信实践的示例代码,分享给大家,具体如下: 因为线程间的内存是共享的,所以它们之间的通信简单,比如可以通过共享变量等方式实现。而进程间想要通信就要麻烦许多了。要想实现进程间通信...
  • 进程间通信的几种方式

    万次阅读 2018-11-28 20:10:00
    在Linux 中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现如下所述。 • 限制管道的大小。实际上,管道是一...
  • 进程间通信方式总结——共享内存

    千次阅读 2017-04-16 11:36:59
    Linux/Unix系统IPC是各种进程间通信方式的统称,但是其中极少能在所有Linux/Unix系统实现中进行移植。随着POSIX和Open Group(X/Open)标准化的推进呵护影响的扩大,情况虽已得到改善,但差别仍然存在。一般来说,...
  • Android 进程间通信方式

    千次阅读 2019-05-15 18:51:53
    Activity,Service,Receiver 都支持在 Intent 中传递 Bundle 数据,而 Bundle 实现了 Parcelable 接口,可以在不同的进程间进行传输。 在一个进程中启动了另一个进程的 Acyivity,Service 和 Receiver ,可以在 ...
  • 首先介绍一下进程和线程的基本概念及两者之间的区别:   进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。   线程:是进程的一个实体,是CPU...
  • 文章从文件映射、命名管道、共享内存、邮件槽等不同进程通信方法出发讲述了其原理和优缺点。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 91,897
精华内容 36,758
关键字:

常用的进程间通信方式