它是更好地使用TThread的"同步"或使用的窗口信息用于IPC之间的主要和儿童线?

StackOverflow https://stackoverflow.com/questions/1806339

  •  05-07-2019
  •  | 
  •  

我有一个相当简单多螺纹VCL gui编写的应用程序,用德尔菲2007年。我做了一些处理多儿童线(最多16个并发的),需要更新的网格控制在我的主要形式(简单地发布串的一个网格)。没有任何儿童线曾经谈到。

我最初的设计参与呼唤 TThread的"同步" 更新的网格控制形式在目前运行的线。然而,我的理解是,这叫同步,基本上执行,如果它是主要的线时叫。16线运行一次(最儿童线的处理需从 < 1第二-10秒)会窗口的消息被一个好的设计?

我已经得到了它的工作在这一点上,那里的孩子线员额windows消息(组成的一个记录的几串)和主线已经侦听和简单的更新的格时消息接收。

任何意见的最佳方法IPC在这种情况?窗口的信息或'同'?

如果我使用的窗口消息,你建议包裹的码在那里我发布到网格中的一TCriticalSection(进入和离开)块?或者我不需要担心线的安全,因为我写的格在主要线(虽然窗口内的信息处理程序的功能)?

有帮助吗?

解决方案

编辑:

它看起来像许多的实施细则已经改变,因为德尔福4和5(Delphi版本的我还在使用我的大部分工作),和艾伦*鲍尔发表了评论意见如下:

自从D6,TThread不使用图了。它使用一线的安全工作队列中的"工作",旨在为主线。一个消息发布主线,以表示工作是提供背景线上的块的事件。当主要信息循环是关于去闲置的,它呼吁"CheckSynchronize"以看到,如果任何工作是在等待。如果是这样,它处理它。一旦一个工作项目完成后,该事件的背景线被阻止设置指示完成。介绍了在D2006的时间框架,TThread.的队列方法加入这并不块。

感谢您的修正。因此,采取的详细信息在原来回答一粒盐。

但是,这并没有真正影响的核心点。我仍然坚持认为,整个想法 Synchronize() 是致命的缺陷,并且这将是显而易见的时刻之一试图让几个核心的现代化机所占据。不是"同步"你的线,让他们的工作,直到他们完成。尝试减少所有之间的依赖关系。特别是在更新GUI有绝对是 没有 原因等待来完成。是否 Synchronize() 使用 SendMessage()PostMessage(), ,所得到的路障是一样的。


什么你在这里是不是一种替代, Synchronize() 使用 SendMessage() 内部。因此,它是更多的问题,武器,你想要用来搬起石头砸自己的脚。

Synchronize() 已经与我们自介绍 TThread 在德尔斐2VCL,这是一个耻辱,真的,因为它是一个较大的设计misfeatures在VCL。

它是如何工作的?它使用一个 SendMessage() 呼叫一个窗口,是建立在主要线,并设置的消息参数,以通过该地址的无参对象的方法被称为。因为窗户的信息将仅处理了在线创建的目的窗口和运行其消息循环,这将暂停线,处理消息上下文中的主要VCL线,调的方法,并恢复该线只有在该方法已经完成的执行。

那么什么是错误(和什么是同样错误的使用 SendMessage() 直接)?几件事情:

  • 迫使任何线的执行代码的上下文中的另外一个线程部队的两个线程的背景下交换机,这毫无必要地伤CPU周期。
  • 而VCL线处理消息叫同步的方法,它不能处理任何其他信息。
  • 当多于一个线程采用这种方法他们会 所有 框并等待 Synchronize()SendMessage() 返回。这创造了一个巨大的瓶颈。
  • 有一个僵局。如果该线电话 Synchronize()SendMessage() 同时保持同步的对象,而VCL线,同时处理信息需要获得相同的同步对象的应用程序将锁。
  • 也可以这样说的API呼叫等待线处理使用 WaitForSingleObject()WaitForMultipleObjects() 没有一些手段过程中的信息将导致僵局,如果在线需要,这些方式"同步"与其他线。

所以有什么用呢?几个选择,我将描述一些:

  • 使用 PostMessage() 而不是的 SendMessage() (或 PostThreadMessage() 如果两个线都不VCL螺纹)。这是很重要的,虽然不使用任何数据的消息参数,将不再有效时,到达的消息,作为发送和接收线是不同步的,所以一些其他手段必须被用来确保任何串,对象参考或大块的记忆仍然有效时的信息进行处理,即使发送线甚至有可能不存在任何的更多。

  • 创建线安全的数据结构,把数据他们自己的工作线程,以及消耗它们的主线。使用 PostMessage() 只要提醒VCL线,新的数据来加以处理,但不要发表消息的每一个时间。如果你有一个连续的数据流你甚至可以有VCL线民意调查的数据(也许通过使用定时器),但这是一个穷人的版本只。

  • 不要使用的低水平的工具,在所有,任何的更多。如果您是至少在德尔斐2007年下载的 OmniThreadLibrary 并开始思考方面的任务,不线。该图书馆拥有大量的设施之间数据交换线和同步。它还有一线的游泳池的执行情况,这是一件好事-有多少线应用并不仅仅取决于应用程序,但也关的硬件上运行,因此许多决定可以在运行时只。信托基金管理费负担将允许运行上的任务线的游泳池线,因此该系统可以调整数的并发线程在运行时间。

编辑:

在重新阅读我知道你不打算使用 SendMessage()PostMessage() -那么,上述某些不适用的话,但我将它留在原地。然而,有一些更点,在你个问题我想要的地址:

16线运行一次(最儿童线的处理需从 < 1第二-10秒)会窗口的消息被一个好的设计?

如果你发布一个消息从每个螺纹每一次第二次,甚至更长的时间,然后设计是好的。你不应该做的是员额数百名或更多的信息,每线每第二,因为Windows消息队具有有限的长度和定制的信息不应干扰正常的消息处理太多了(你的节目就开始出现反应迟钝).

那里的儿童线员额windows消息(组成的一个记录的几串)

一个窗口信息可以不包含记录。它携带了两个参数之一的类型 WPARAM, ,其他的类型 LPARAM.你只能投一个指向这样一个记录到这些类型之一,因此终身的记录需要加以管理。如果你的动态分配它,你需要自由了,这很容易出现错误。如果你通过一个指向记录上的叠或对象领域的需要,以确保它仍然是有效的消息时的处理,这是更困难的发布消息比对发送消息。

做你的建议包裹的码在那里我发布到网格中的一TCriticalSection(进入和离开)块?或者我不需要担心线的安全,因为我写的格在主要线(虽然窗口内的信息处理程序的功能)?

有没有必要这样做,为的 PostMessage() 呼叫立即返回,所以没有同步是必要的 在这一点.你肯定会需要担心线的安全,不幸的是,你不可能知道 .你必须确保对数据的访问是线安全通过 总是 锁定的数据接入、使用同步的对象。没有真正的方式来实现,为记录、数据总是可以直接访问。

其他提示

顺便说一下,你也可以使用 TThread.Queue( ) 而不是 TThread。同步() Queue()是异步版本,它不会阻塞调用线程:

(自D8起,队列可用)。

我更喜欢 Synchronize() Queue(),因为它比普通的消息发送更容易理解(对于其他程序员)和更好的OO(没有控制权)关于它或能够调试它!)

虽然我确信有正确的方法和错误的方式。我使用这两种方法编写代码,而我一直在返回的是SendMessage方法,我不知道为什么。

使用SendMessage vs Synchronize并没有什么区别。两者的工作基本相同。我认为我继续使用SendMessage的原因是我感觉到更多的控制,但我不知道。

SendMessage例程使调用线程暂停并等待,直到目标窗口完成处理发送的消息。因此,主要应用程序线程在调用期间基本上与调用子线程同步。您不需要在Windows消息处理程序中使用临界区。

数据传输本质上是从调用线程到主应用程序线程的一种方式。您可以在message.result中返回整数类型值,但不指向主线程中的内存对象。

由于两个线程是“同步”的,因此那个点和主要的应用程序线程目前被绑定响应SendMessage然后你也不需要担心其他线程进入并同时丢弃你的数据。因此,您不必担心使用关键部分或其他类型的线程安全措施。

对于简单的事情,您可以定义单个消息(wm_threadmsg1)并使用wparam和lparam字段来回传输(整数)状态消息。对于更复杂的示例,您可以通过将其传递给lparam并将其转换回longint来传递字符串。 A-la longint(pchar(myvar))或使用pwidechar,如果您使用D2009或更新版本。

如果你已经使用了Synchronize方法,那么我就不用担心重做它来进行更改。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top