首页 > 系统相关 >进程间通信与线程间通信的方法汇总

进程间通信与线程间通信的方法汇总

时间:2024-08-03 20:28:40浏览次数:8  
标签:映射 汇总 间通信 线程 内存 进程 共享内存

目录

一、进程间通信机制

管道(pipe):

命名管道(FIFO):

消息队列(MQ):

信号量(semaphore):

共享内存(shared memory):

信号(signal):

内存映射(mapped memory):

内存映射和共享内存的区别

Socket:

二、线程间通信与同步机制

Linux平台下:

信号(Signal):

锁机制:

条件变量(Condition Variable):

信号量(Semaphore):

Windows平台下:

全局变量:

Message 消息机制:

CEvent 对象:

为什么Linux和Windows的线程通信的实现方式完全不同呢?


无论进程还是线程,通信的本质都是让不同的执行流“看到”同一份资源!!!

一、进程间通信机制

管道(pipe)

管道允许两个有血缘关系的(父子、兄弟等)进程之间的通信。管道是一种半双工的通信方式,数据只能单向流动。例如,父进程向子进程发送数据,或者子进程向父进程发送数据。

原理是通过父子进程的继承关系以及关闭不需要的文件描述符来实现进程间通信

命名管道(FIFO)

类似于管道,但它可以用于任何两个进程之间的通信。通过命令 mkfifo 或系统调用 mkfifo 来创建。例如,在不同用户的进程之间,只要具有适当的权限,就可以通过命名管道进行通信。

命名管道在文件系统中有对应的文件名,在内核中为命名管道维护一个缓冲区,用于存储写入的数据。

消息队列(MQ)

消息队列是消息的连接表,包括 POSIX 消息队列和 System V 消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少、管道只能传输无格式字节流以及缓冲区大小受限等缺点。

比如,在一个分布式系统中,不同的子系统可以通过消息队列来传递各种类型和规模的数据。

信号量(semaphore)

信号量主要作为进程间以及同进程不同线程之间的同步手段。它可以用于控制对共享资源的访问,确保多个进程或线程不会同时访问和修改共享资源,从而避免冲突和错误。

例如,在一个多线程的数据库操作中,使用信号量来控制对数据库连接的并发访问。

共享内存(shared memory)

共享内存允许多个进程直接访问同一块物理内存区域,避免了数据在不同进程之间相互拷贝开销,是最快的可用 IPC 形式。这是针对其他通信机制运行效率较低而设计的。它往往与其他通信机制,如信号量结合使用,以达到进程间的同步及互斥。

比如,在一个高性能计算的场景中,多个进程需要频繁地交换大量数据,共享内存可以极大地提高通信效率。

信号(signal)

信号是比较复杂的通信方式,用于通知接收进程有某种事情发生。除了用于进程间通信外,进程还可以发送信号给进程本身。

例如,当一个进程出现错误或异常情况时,可以向其他相关进程发送信号,以便它们采取相应的处理措施。

内存映射(mapped memory)

内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件或内存区域映射到自己的进程地址空间来实现它,它也是一种相比于其他方式而言很快的通信方式。

比如,多个进程可以同时映射同一个大文件,从而实现对文件内容的快速访问和处理。

在 Windows 中,内存映射文件(Memory-Mapped Files)提供了类似于内存映射的功能,允许进程将文件或一块内存区域映射到其地址空间。

内存映射和共享内存的区别

内存映射和共享内存都是进程间通信的有效方式,但它们在实现和应用上存在一些区别:

实现方式

  • 内存映射:通过将文件或特定的内存区域映射到进程的地址空间来实现通信。可以是基于文件的内存映射,也可以是匿名的内存映射。
  • 共享内存:专门在操作系统内核中创建一块可供多个进程共同访问的内存区域。

数据来源

  • 内存映射:数据通常来源于文件。
  • 共享内存:数据可以由进程自行初始化和填充。

同步机制

  • 内存映射:依赖于文件的同步机制,例如文件锁。
  • 共享内存:通常需要额外的同步机制,如信号量,来协调多个进程对共享内存的访问,以避免数据竞争和不一致。

适用场景

  • 内存映射:适用于需要处理大文件数据、在进程间共享文件内容或对文件进行随机访问的情况。
  • 共享内存:适用于需要快速、高效地在进程间共享大量数据,且对数据的实时性和交互性要求较高的场景。

复杂性

  • 内存映射:相对来说实现较为简单,特别是基于文件的映射。
  • 共享内存:需要更复杂的同步策略来保证数据的一致性和正确性。

例如,在一个图像处理系统中,如果需要在多个进程间共享图像数据,且数据量较大、对速度要求高,可能会选择共享内存,并搭配信号量进行同步;而如果需要在进程间共享一个配置文件的内容,更适合使用内存映射。

Socket

它是更为通用的进程间通信机制,可用于不同主机之间的进程间通信。

例如,在网络环境中,不同主机上的进程可以通过 Socket 进行通信,实现分布式应用的协同工作。

二、线程间通信与同步机制

Linux平台下:

信号(Signal)

它类似于进程间的信号处理,是一种异步通信方式。它允许一个线程向另一个或多个线程发送特定的信号,以通知某些事件的发生。

锁机制

  1. 互斥锁(Mutex Lock):确保在同一时刻只有一个线程能够访问被保护的资源,实现了资源的独占访问。例如,在多线程访问共享数据库连接时,使用互斥锁来保证同一时间只有一个线程能获取和使用该连接。
  2. 读写锁(Read-Write Lock):区分读操作和写操作的锁机制。允许多个线程同时进行读操作,但在写操作时进行独占锁定。对于一个频繁读取但偶尔修改的数据结构,读写锁可以提高并发性能。
  3. 自旋锁(Spin Lock):线程在获取锁时,如果锁不可用,会持续循环尝试获取,而不是进入阻塞状态。适用于短时间等待且线程切换开销较大的场景。在多核系统中,处理一些简单的临界区操作时,自旋锁可以避免线程切换的开销。

条件变量(Condition Variable)

用于线程同步的一种机制,条件变量通常与互斥锁配合使用,用于解决线程之间等待和通知。

条件变量的主要作用是: 当某个条件不满足时,线程可以阻塞等待在条件变量上;当条件满足时,其他线程可以通知等待在该条件变量上的线程继续执行。

例如,在生产者-消费者模型中,消费者线程在缓冲区为空时等待条件变量,生产者线程在生产数据后通知条件变量,唤醒消费者线程。

信号量(Semaphore)

包括无名线程信号量和命名线程信号量。信号量用于控制对共享资源的访问数量,确保同时访问的线程或进程数量不超过限制。

比如,限制同时访问打印机的进程数量。

Windows平台下:

全局变量

当需要有多个线程来访问一个全局变量时,通常会在这个全局变量前加上 volatile 声明,以防编译器对此变量进行优化。volatile 关键字告诉编译器每次都从内存中读取变量的值,而不是使用可能的缓存值。

Message 消息机制

常用的 Message 通信的接口主要有两个:PostMessage 和 PostThreadMessage 。

  1. PostMessage :线程向主窗口发送消息。
    • 例如,在一个多线程的图形界面应用中,工作线程可以使用 PostMessage 向主窗口发送更新界面的请求。
  2. PostThreadMessage :任意两个线程之间的通信接口。
    • 比如,在一个后台计算线程和一个数据展示线程之间,可以通过 PostThreadMessage 传递计算结果和控制指令。

CEvent 对象

CEvent 为 MFC 中的一个对象,可以通过对 CEvent 的触发状态进行改变,从而实现线程间的通信和同步,这主要是实现线程直接同步的一种方法。

CEvent 对象具有两种状态:有信号状态和无信号状态。线程可以通过等待 CEvent 对象的状态变化来进行同步和通信。

Linux 平台下的条件变量与 Windows 中的 CEvent 对象有一些相似之处。

相似点:

  1. 都用于线程之间的同步和通信。
  2. 都可以让线程处于等待状态,直到特定条件满足。

为什么Linux和Windows的线程通信的实现方式完全不同呢?

因为两个系统在内核中对线程的实现方式就是完全不同的:

  • Linux 把线程当作进程来实现,内核并没有准备特别的调度算法或是定义特别的数据结构来表示线程,而是将线程仅仅视为一个与创建进程共享系统分配的资源的进程,每个线程都拥有唯一隶属于自己的 task_struct,所以在内核中,线程看起来更像是一个轻量级进程。
  • Windows 则专门设计了支持内核线程的机制,它在每个 task_struct 内为每个内核级线程提供了 tcb 控制块,每个 tcb 用于描述自己的独立的资源,并且支持创建核心级线程来并行执行某一个进程的多个核心级线程。

标签:映射,汇总,间通信,线程,内存,进程,共享内存
From: https://blog.csdn.net/weixin_73567058/article/details/140808953

相关文章

  • Java通过redis实线多线程多用户操作时添加锁
    背景由于项目中多出涉及同步数据,同步过程就是从设备上查询数据,将数据库中该设备数据删除,将新数据导入到数据库;多次同步数据或多用户操作,会导致数据库出现重复数据,例如,两个线程同时删除设备数据,同时导入数据,就会出现双倍数据;还有线程1正在导入数据,中途线程2将线程1导入数据之前删......
  • Java使用多线程池给List赋值导致List存在空的处理
    错误示例:publicList<String>test()throwsNuMaxCloudCommonException{ExecutorServiceexecutorService=Executors.newFixedThreadPool(3);List<String>list=newArrayList<>();for(inti=0;i<3;i++){......
  • 57_2设置Servlet模板、Servlet线程安全问题、跳转
    设置Servlet模板再创建类就有了模板代码#if(${PACKAGE_NAME}&&${PACKAGE_NAME}!="")package${PACKAGE_NAME};#end#parse("FileHeader.java")importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servl......
  • nodejs使用child_process模块启动(exec和spawn)子线程任务,子进程实例的kill()方法无效的
    以下内容在win10环境下的执行分析(这里就不对进程和线程做区分了):child_process.exec和child_process.spawn启动进程的区别。shell<string>Shelltoexecutethecommandwith.SeeShellrequirementsandDefaultWindowsshell.Default:'/bin/sh'onUnix,process.env.C......
  • 【QT】Qt 多线程
    多线程qt多线程1.Qt多线程概述2.QThread常用API3.使用线程4.线程安全(1)互斥锁(2)条件变量(3)信号量qt多线程1.Qt多线程概述在Qt中,多线程的处理⼀般是通过QThread类来实现。QThread代表⼀个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享......
  • 直播软件怎么开发,你还在为如何创建线程池发愁吗?
    直播软件怎么开发,你还在为如何创建线程池发愁吗?为什么要使用多线程提高响应速度:对于耗时操作,使用线程可以避免阻塞主线程,提高应用程序的响应速度。实现并行操作:在多CPU系统中,使用线程可以并行处理任务,提高CPU利用率。改善程序结构:将一个既长又复杂的进程分为多个线程,可以使其......
  • 深度解码:Java线程生命周期的神秘面纱
    在Java的编程宇宙中,线程是驱动应用程序的微小而强大的引擎。它们就像心脏的跳动,维持着程序的活力和响应性。今天,我们将深入探究线程的生命周期,理解它们从诞生到消逝的全过程,以及如何在不同状态下优雅地过渡。第二章:线程的活跃岁月执行阶段:运行与忙碌一旦被CPU选中,线程开......
  • 使用线程池你应该知道的知识点
    多线程编程是每一个开发必知必会的技能,在实际项目中,为了避免频繁创建和销毁线程,我们通常使用池化的思想,用线程池进行多线程开发。线程池在开发中使用频率非常高,也包含不少知识点,是一个高频面试题,本篇总结线程池的使用经验和需要注意的问题,更好的应对日常开发和面试。如有更多知......
  • 程序员进阶架构知识体系、开发运维工具使用、Java体系知识扩展、前后端分离流程详解、
    场景作为一名开发者,势必经历过从入门到自学、从基础到进阶、从学习到强化的过程。当经历过几年企业级开发的磨炼,再回头看之前的开发过程、成长阶段发现确实是走了好多的弯路。作为一名终身学习的信奉者,秉承持续学习、持续优化的信念。不惜耗费无数个日日夜夜,耗费大量时间精力......
  • Java:进程和线程
    文章目录进程线程的概念和区别总结如何创建线程1.继承Thread重写run2.实现Runnable重写run3.继承Thread重写run,通过匿名内部类来实现虚拟线程并发编程:通过写特殊的代码,把多个CPU核心都利用起来,这样的代码就称为“并发编程”。多进程编程,就是一种典型的并发编程......