0

我有一个使用 pthreads 的多线程应用程序。我有一个互斥锁()锁和条件变量()。有两个线程,一个线程正在为第二个线程(一个工作线程)生成数据,该线程正在尝试以实时方式处理生成的数据,以便在尽可能接近固定时间段过去的情况下处理一个卡盘。

这工作得很好,然而,偶尔当生产者线程释放工作者正在等待的条件时,在工作者线程获得控制权并再次执行之前,会出现长达近一秒的延迟。

我知道这一点,因为在生产者释放工人正在等待的条件之前,如果是时候处理另一个卡盘,它会为工人做一个卡盘处理,然后在工作线程中接收到条件后,它也会立即执行如果是时候加工另一个夹头,则加工一个夹头。

在后一种情况下,我看到我处理卡盘很多次都晚了。我想消除这种损失的效率,并尽我所能保持卡盘的滴答声尽可能接近所需的频率。

我能做些什么来减少生产者的释放条件与检测到该条件已释放以使工作人员恢复处理之间的延迟吗?例如,生产者调用某些东西来强制自己切换上下文是否会有所帮助?

底线是工人必须等待每次它要求生产者为自己创建工作,以便生产者可以在告诉工人它准备好再次并行运行之前与工人的数据结构混淆。生产者的独占访问时间很短,但在此期间,我也在检查生产者代表工人完成的实时工作,而生产者具有独占访问权限。不知何故,我的手重新回到并行运行,偶尔会导致我想避免的显着延迟。请建议如何最好地实现这一点。

4

1 回答 1

2

我可以建议以下模式。通常可以使用相同的技术,例如在某些实时渲染器中预缓冲帧或类似的东西时。

首先,很明显,您在消息中描述的方法只有在您的两个线程始终平等(或几乎平等)加载时才会有效。如果没有,多线程实际上会在您的情况下受益。

现在,让我们考虑一个最适合您的问题的线程模式。假设我们有一个yielding和一个processing线程。他们首先准备要处理的数据块,第二个进行处理并将处理结果存储在某处(实际上并不重要)。

使这些线程一起工作的有效方法是适当的让步机制。您的yielding线程应该简单地将数据添加到某个共享缓冲区,并且实际上不应该关心该数据会发生什么。而且,你的缓冲区可以实现为一个简单的 FIFO 队列。这意味着您的yielding线程应该准备要处理的数据并PUSH调用您的队列:

X = PREPARE_DATA()
BUFFER.LOCK()
BUFFER.PUSH(X)
BUFFER.UNLOCK()

现在,processing线程。它的行为应该这样描述(你可能应该SLEEP(X)在调用之间添加一些人为的延迟EMPTY

IF !EMPTY(BUFFER) PROCESS(BUFFER.TOP)

这里的重要时刻是您的处理线程应该如何处理处理过的数据。显而易见的方法是POP在处理完数据后进行调用,但您可能想要一些更好的主意。无论如何,在我的变体中,这看起来像

// After data is processed
BUFFER.LOCK()
BUFFER.POP()
BUFFER.UNLOCK()

请注意,线程中的锁定操作yielding实际上processing不应影响您的性能,因为它们仅在每个数据块中调用一次。


现在,有趣的部分。正如我在开头所写的那样,这种方法只有在线程在 CPU / 资源使用方面的行为有点相同时才会有效。有一种方法可以使这些线程解决方案有效,即使这种情况并非始终正确并且对其他一些运行时条件很重要。

这种方式意味着创建另一个称为线程的controller线程。该线程将仅比较每个线程用于处理一块数据的时间并相应地平衡线程优先级。实际上,我们不必“比较时间”controller线程可以简单地像这样工作:

IF BUFFER.SIZE() > T
   DECREASE_PRIORITY(YIELDING_THREAD)
   INCREASE_PRIORITY(PROCESSING_THREAD)

当然,您可以在这里实现一些更好的启发式方法,但是使用controller线程的方法应该很清楚。

于 2010-05-24T06:16:19.113 回答