我有一个使用pthreads的多线程应用程序。我有一个mutex()锁和条件变量()。有两个线程,一个线程正在为第二个线程生成数据,一个工作者,它试图以实时方式处理所产生的数据,使得一个卡盘被处理为尽可能接近固定时间段的流逝。
这非常有效,但是,当生产者线程释放工作者正在等待的条件时,偶尔会在工作线程获得控制并再次执行之前看到几乎整整一秒的延迟。
我知道这是因为在生产者发布工人等待的条件之前,如果是时候处理另一个夹头,那么它会立即为工人进行处理,然后在工人线程中收到条件后立即执行,如果是时候处理另一个夹头,它也会进行处理。
在后一种情况下,我看到我多次处理夹头。我想消除这种失去的效率,并尽我所能保持夹头尽可能接近所需的频率。
我能做些什么来减少生产者的释放条件与检测到该条件被释放以使工人恢复处理之间的延迟?例如,是否有助于生产者调用某些东西来强迫自己被上下文切换出来?
底线是工作人员每次要求生产者为自己创建工作时必须等待,以便生产者可以在告诉工人准备再次并行运行之前清理工人的数据结构。生产者独家访问的这段时间意味着很短,但在此期间,我还要检查生产者代表工人完成的实时工作,而生产者可以独家访问。不知怎的,我的手又回到并行运行会偶尔导致我想避免的显着延迟。请建议如何最好地完成这项工作。
答案 0 :(得分: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
线程的方法应该是明确的。