进程间通信与线程间通信

本文探讨了操作系统中进程和线程的通信机制,包括管道、有名管道、消息队列、信号量、共享内存和信号等。这些通信方式各有特点,如管道的单向传输,有名管道的命名特性,信号量的同步作用,共享内存的高效通信,以及信号的异步通知功能。此外,还提到了套接字在进程间通信中的应用,特别是在网络通信中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         以前一直想找个机会总结一下进程和线程的通信机制,但由于技术和平台的局限性,一直没有找准切入点。由于马上要毕业了,对自己技术的总结和梳理的前提下写了本篇文章,如有错误之处,敬请拍砖和指教。

         操作系统的主要任务是管理计算机的软件、硬件资源。现代操作系统的主要特点是多用户和多任务,也就是程序的并行执行,windows如此linux也是如此。所以操作系统就借助于进程来管理计算机的软、硬件资源,支持多任务的并行执行。要并行执行就需要多进程、多线程。因此多进程和多线程间为了完成一定的任务,就需要进行一定的通信。而线程间通信又和进程间的通信不同。由于进程的数据空间相对独立而线程是共享数据空间的,彼此通信机制也很不同。

         线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。

         进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了网络通信。

        进程的通信机制主要有:管道、有名管道、消息队列、信号量、共享空间、信号、套接字。

        管道:它传递数据是单向性的,只能从一方流向另一方,也就是一种半双工的通信方式;只用于有亲缘关系的进程间的通信,亲缘关系也就是父子进程或兄弟进程;没有名字并且大小受限,传输的是无格式的流,所以两进程通信时必须约定好数据通信的格式。管道它就像一个特殊的文件,但这个文件之存在于内存中,在创建管道时,系统为管道分配了一个页面作为数据缓冲区,进程对这个数据缓冲区进行读写,以此来完成通信。其中一个进程只能读一个只能写,所以叫半双工通信,为什么一个只能读一个只能写呢?因为写进程是在缓冲区的末尾写入,读进程是在缓冲区的头部读取,他们各自 的数据结构不同,所以功能不同。

        有名管道:看见这个名字就能知道个大概了,它于管道的不同的是它有名字了。这就不同与管道只能在具有亲缘关系的进程间通信了。它提供了一个路径名与之关联,有了自己的传输格式。有名管道和管道的不同之处还有一点是,有名管道是个设备文件,存储在文件系统中,没有亲缘关系的进程也可以访问,但是它要按照先进先出的原则读取数据。同样也是单双工的。

        消息队列:是存放在内核中的消息链表,每个消息队列由消息队列标识符标识,于管道不同的是,消息队列存放在内核中,只有在内核重启时才能删除一个消息队列,内核重启也就是系统重启,同样消息队列的大小也是受限制的。

        信号量:也可以说是一个计数器,常用来处理进程或线程同步的问题,特别是对临界资源的访问同步问题。临界资源:为某一时刻只能由一个进程或线程操作的资源,当信号量的值大于或等于0时,表示可以供并发进程访问的临界资源数,当小于0时,表示正在等待使用临界资源的进程数。更重要的是,信号量的值仅能由PV操作来改变。

        共享内存:就是分配一块能被其他进程访问的内存。共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。首先说下在使用共享内存区前,必须通过系统函数将其附加到进程的地址空间或说为映射到进程空间。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到 进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互 斥锁和信号量都可以。采用共享内存通信的一个显而易 见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而 共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就 解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存 中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。

         信号:信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源。信号分为可靠信号和不可靠信号,实时信号和非实时信号。进程有三种方式响应信号1.忽略信号2.捕捉信号3.执行缺省操作。

        套接字:这一块在网络编程那一块讲的 很多,在此就不在说拉。

Linux系统支持多种进程间通信(IPC,Inter-Process Communication)以及线程间通信的方式。理解这两者的区别及其实现机制对于编写高效的并发程序至关重要。 ### 进程间通信 1. **管道(Pipe)**:最简单的形式之一,适用于有亲缘关系的两个进程之间进行单向数据传递。匿名管道仅限于父子进程间的通讯;命名管道则可以跨越无血缘关系的进程。 2. **消息队列(Message Queue)**:允许一个或多个进程将信息发送到另一个进程中存储的消息列表里,并从该列表读取消息。它具备更强的功能性和灵活性比普通文件更高效地处理小块的数据交换任务。 3. **信号量(Semaphore)** 和**共享内存(Shared Memory)**: - *信号量*用于控制对资源访问权限的数量限制,保证同步协调工作。 - *共享内存段*提供了一种快速存取大容量数据的有效途径,使得不同进程可以直接操作共同开辟的一片虚拟地址空间内的内容。 4. **套接字(Socket)**:不仅能在本地机器的不同应用程序间建立连接,而且能通过网络其他计算机上运行的服务端口相互通信,是最具通用性的跨平台方案。 5. **信号(signal)**:主要用于通知接收方发生了某些特定事件,比如用户按键中断、硬件错误等非正常情况下的即时反馈机制。 --- ### 线程间通信 在同一进程中创建出来的各个线程由于共享相同的上下文环境(包括全局变量表、堆栈指针寄存器值),因此它们之间的交互更为直接紧密: 1. **互斥锁(mutex lock)** 及其他类型的 锁结构 :如读写锁(read-write locks),条件变元(condition variables) ,自旋锁(spinlocks), etc., 主要是用来解决临界区竞争问题,即当多个线程试图同时修改同一份数据时如何确保一致性。 2. **事件(event signaling)** 或者说是基于等待唤醒模式的工作流设计,在某个条件下让某几个指定的参者得到提示继续前进而不再阻塞下去。 3. **原子操作(atomical operations)**:在现代多核处理器架构下提供的底层汇编指令级的支持功能,能够一次性完成增减计数器之类的简单动作而不必担心中途被打断造成混乱局面发生。 总之,无论是选择哪种方式进行交流沟通都应当考虑到效率损耗成本、可移植性因素等方面的影响做出合理决策。 --
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值