您的问题非常广泛。
有许多可用选项,最适合您的选项取决于您的特定需求和环境。您需要提供有关希望主线程在运行器线程上更新的数据类型的更多详细信息。预计多久更新一次?您已经说过运行器线程是时间关键的 - 这意味着您想要保持锁定(PS:多线程应用程序中减速的主要来源是不同线程竞争相同的锁。称为锁竞争。)到最低限度。 (正如我所说:这取决于您的需求。)
PS:必须使用主线程设置的所有数据吗?或者运行器线程是否可以简单地使用最新的可用数据而忽略可能已分配的许多中间值? 这个问题的答案产生了根本不同的选择。
例如,原子更新可以在没有任何锁定的情况下执行。看看TThread.Terminated。这是一个简单的值。您不需要任何锁来更新此特定值。不存在有问题的竞争条件,因为处理器会将值作为整个原子单元读取或写入。
即使您同时更新 while not Terminated 循环正在读取该值 - 也不会有问题。更新要么发生在读取之前(导致线程退出循环),要么发生在之后(导致在下一次读取时循环退出之前再进行一次迭代)。
PS:请务必注意,设置字符串值不是原子操作。
现在您已经表明主线程根本不需要读取运行线程的数据。但我会用这种可能性作为对比的例子。如果您需要在 runner 线程上增加一个整数值,那需要保护。这是因为增加一个值是一个多步操作:
如果运行线程和主线程同时使用该值,可能会得到不一致的结果。
另一种可能导致问题的情况是数据由许多相互交互的值组成。例如。 NoOfUnits 和MassPerUnit 组合使用以确定TotalMass。独立更新这些值可能会导致竞争条件导致行为不一致。
Silver Warrior's answer 提供了一种保护多个值的技术。尽管请注意,该答案的当前版本存在一些严重错误。
请注意,如果您将数据封装在单独的对象中,则可以在没有任何锁的情况下更新运行器线程的数据,因为您可以原子地更新指针值。 (非常注意:您必须遵循许多特殊规则,并且您需要弄清楚如何避免内存泄漏......但这是更具体问题的详细信息。 )
另一种选择是将运行器线程实现为消息队列。 IE。当主线程想要更改值时,它会向运行线程发送一条消息。跑步者只会在“安全”的情况下处理更改后的值指令。 (同样,这是否可行取决于您的具体要求。)
作为最后一点,除了保护数据免受竞争条件之外,还有一些额外的问题。您的跑步者线程究竟时间有多紧迫?它做了多少处理?它是否需要快速响应某些事件?如果有,是什么事件?
这些问题的答案对于理解运行器线程主循环的理想结构非常重要。例如,一个“繁忙循环”(一个可能迭代而不做任何事情只是为了确保它永远不会暂停的循环)会使线程高度响应,但会使机器资源匮乏并使其整体变慢。相比之下,消息队列通常会运行一个循环处理消息,直到没有消息为止,然后将线程置于“等待状态”,直到收到下一条消息。
PS:另一个潜在的争用和减速源是内存管理器。如果您的主线程和运行线程都执行大量堆分配/解除分配,您可能会在您甚至没有明确编码的区域发生锁争用。