delphi线程通信的一种方式?

时间:2015-01-02 02:16:15

标签: multithreading delphi variables

考虑我的Delphi程序有两个线程。

当然主要的一个和一个跑步者线程(总是运行它永远不会停止)。

我想知道在跑步者线程中更新变量(16个原子整数)的最佳方法是什么,而不会产生问题。

转轮线程始终包括通过USB发送低电平数据(时间要求<10 ms)。

我只需要一种方法,因为转轮线程永远不会向主线程报告。

有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

如果你正在考虑暴露正在运行的线程的一些变量,然后用主线程更改这些变量,请不要这样做!我真的是这个意思。 DON&#39; T!

为什么不呢?因为你的主线程永远都不知道何时可以安全地更改这些变量,并且最终可能会在转轮线程读取它们的同时更改它们。

所以我会创建一个包含所有变量的记录,但该记录不在你的跑步者范围内。

然后我会确保对此记录中的数据所做的所有更改都受到关键部分的保护。这是为了确保只有一个线程同时访问该记录。

然后在你的跑步者线程中,我将从该记录中读取数据并制作本地副本(这个是在你正在运行的线程中)。现在阅读记录再次受到关键部分的保护。

现在您可能会问自己为什么我会从正在运行的线程中读取这些变量的数据。这样做的主要原因是你正在运行的线程是那些现在可以更新这些变量中的数据而不是更新的线程。

我将变量数据存储在记录中的原因是为了使临界区的进入和离开尽可能快。
您可以看到,当您使用关键部分进入临界区时,将锁定您将在关键部分内访问的所有变量。因此,如果您有多个这样的过程可能需要一段时间,因为变量被逐个锁定。但如果您将所有变量存储在记录中,则进入临界区将立即锁定整个记录 当离开临界区并且解锁对变量的访问时,同样适用。

答案 1 :(得分:3)

你的问题很广泛。

有多种选择,最适合您的选择取决于您的具体需求和环境。您需要提供有关您希望主线程在转轮线程上更新的数据类型的更多详细信息。预计更新的频率如何?你已经说过,转轮线程是时间关键的 - 这意味着你要保持锁定( PS :多线程应用程序中减速的主要来源是不同的线程竞争相同时锁。称为锁争用。)到最小的最小值。 (正如我所说:这取决于您的需求。)

PS :必须使用主线程设置的所有数据吗?或者,流媒体线程是否可以简单地使用最新的可用数据,但是可能已分配了许多中间值? 这个问题的答案产生了根本上不同的选择


例如,可以在没有任何锁定的情况下执行原子更新。看TThread.Terminated。这是一个简单的价值。您不需要任何锁来更新此特定值。没有问题的竞争条件,因为处理器将读取或写入整个原子单元的值。

即使您在while not Terminated循环正在读取值的同时进行更新 - 也不会出现问题。更新将在读取之前发生(导致线程退出循环),或者它将在之后发生(导致在下一次读取循环退出之前再进行一次迭代)。

PS :了解设置字符串值原子操作非常重要。

现在您已经表明主线程根本不需要读取转轮线程的数据。但我将这种可能性作为一个对比的例子。如果您需要在运行程序线程上增加整数值,那么 将需要 保护。这是因为递增值是一个多步操作:

  • 阅读价值。
  • 对读取的值执行计算。
  • 写一个新值。

如果主线程的转轮线程同时使用该值,则可能会得到不一致的结果。

另一种可能导致问题的情况是数据由多个彼此交互的值组成。例如。 NoOfUnitsMassPerUnit组合使用以确定TotalMass。独立更新这些值可能会导致竞争条件导致行为不一致。

Silver Warrior's回答提供了一种保护多个值的技巧。虽然请注意当前版本的答案中存在一些严重错误。

请注意,如果您将数据封装在一个单独的对象中,则可以在没有任何锁定的情况下更新您的跑步者线程数据,因为您可以更新指针值原子。 (非常注意:您必须遵循一些特殊规则,并且您需要弄清楚如何避免内存泄漏......但是有关更具体问题的详细信息。)

另一种选择是将您的跑步者线程实现为消息队列。即当主线程想要更​​改值时,它会向运行程序线程发送一条消息。跑步者只会在安全&#34;安全&#34;这样做。 (同样可行性取决于您的具体要求。)


作为最后一点,除了竞争条件之外,还有一些其他问题需要保护数据。完全时间关键如何成为你的跑步者线程?它做了多少处理?是否需要对某些事件做出快速反应?如果是这样,会发生什么事?

这些问题的答案对于理解跑步者线程主循环的理想结构非常重要。例如,一个忙碌的循环&#34; (一个可以迭代但不做任何事情只是为了确保它永远不会暂停的循环)会使线程高度响应,但会使资源机器匮乏并使其整体减速。相比之下,消息队列通常会运行循环处理消息,直到没有剩余,然后将线程置于&#34;等待状态&#34;直到收到下一条消息。

PS :内存管理器是另一个潜在的争用和减速源。如果主线程和运行线程都执行大量的堆分配/解除分配,则可能会在您甚至没有显式编码的区域中获得锁争用。