线程通信理论

Posted

技术标签:

【中文标题】线程通信理论【英文标题】:Thread communication theory 【发布时间】:2009-02-17 02:04:12 【问题描述】:

线程通信背后的共同理论是什么?我对它应该如何工作有一些原始的想法,但有些东西对我来说并不好。有没有办法通过中断来做到这一点?

【问题讨论】:

【参考方案1】:

真的,这与任何并发问题相同:您有多个控制线程,并且不确定何时在哪些线程上执行哪些语句。这意味着程序中有大量的 POTENTIAL 执行路径,你的程序必须在所有这些路径下都是正确的。

一般来说,可能出现问题的地方是线程之间共享状态(过去也称为“轻量级进程”)。当有共享内存区域时,就会发生这种情况,

为确保正确性,您需要做的是确保以不会导致错误的方式更新这些数据区域。为此,您需要识别程序的“关键部分”,其中必须保证顺序操作。这些可以少到一条指令或一行代码;如果语言和架构确保这些是原子的,即不能被中断,那么你就是黄金。

否则,您将识别该部分,并在其上设置某种保护措施。经典的方法是使用 semaphore,这是一种原子语句,一次只允许一个控制线程通过。这些是由 Edsgar Dijkstra 发明的,因此有来自荷兰语、PV 的名称。当你来到一个P时,只有一个线程可以继续;所有其他线程都排队等待,直到正在执行的线程进入相关的 V 操作。

因为这些原语有点原始,而且荷兰语名称不是很直观,所以已经开发了一些更大规模的方法。

Per Brinch-Hansen 发明了 monitor,它基本上只是一种数据结构,具有保证原子的操作;它们可以用信号量来实现。监视器几乎是 Java synchronized 语句的基础;它们使对象或代码块具有特定的行为——也就是说,一次只能有一个线程“进入”它们——语法更简单。

还有其他可能的模式。 Haskell 和 Erlang 通过函数式语言解决了这个问题,它们一旦创建就不允许修改变量;这意味着他们自然不需要担心同步问题。一些新的语言,比如 Clojure,有一个称为“事务性内存”的结构,这基本上意味着当有 赋值时,你可以保证赋值是原子的和可逆的。

简而言之就是这样。要真正了解它,查看操作系统文本的最佳位置,例如 Andy Tannenbaum's text。

【讨论】:

【参考方案2】:

两种最常见的线程通信机制是共享状态和message passing。

【讨论】:

【参考方案3】:

线程最常见的通信方式是通过一些共享数据结构,通常是队列。一些线程将信息放入队列,而另一些则将其取出。队列必须受到操作系统设施的保护,例如互斥锁和信号量。中断与它无关。

【讨论】:

在一些精心控制的情况下可以使用无锁队列。但是您仍然需要操作系统的一些帮助,以防止您的队列阅读器忙于等待。 “nutexes and senaphores”应该是“mutexes and semaphores”【参考方案4】:

如果您真的对线程通信的理论感兴趣,您可能需要研究像pi Calculus 这样的形式。

【讨论】:

【参考方案5】:

要在线程之间进行通信,您需要使用操作系统和/或运行时提供的任何机制。中断将异常低级别,尽管如果您的线程使用套接字或命名管道进行通信,它们可能会被隐式使用。

一种常见的模式是使用共享内存块实现共享状态,依靠操作系统提供的同步原语(例如互斥锁)来避免您在从块中读取时忙于等待。请记住,如果您有线程,那么您必须已经有某种调度程序(无论它是来自操作系统的本机还是在您的语言运行时中模拟)。所以这个调度器可以提供同步对象和“睡眠”功能,而不必依赖硬件支持。

套接字、管道和共享内存也在进程之间工作。有时,运行时会为您提供一种更轻量级的方式来为同一进程中的线程进行同步。共享内存在单个进程中更便宜。有时您的运行时还会为您提供原子消息传递机制。

【讨论】:

以上是关于线程通信理论的主要内容,如果未能解决你的问题,请参考以下文章

线程间的通信

进程与线程的区别,进程间通信方式,线程间通信方式

iOS开发多线程篇—线程间的通信

13.6 线程通信

13.6 线程通信

等待与唤醒机制(线程之间的通信)