gpt4 book ai didi

c++ - 为什么我的线程有时会出现 "stutter"?

转载 作者:可可西里 更新时间:2023-11-01 15:27:58 26 4
gpt4 key购买 nike

我正在尝试编写一些多线程代码以从 DAQ 设备读取并同时呈现捕获的信号:

std::atomic <bool> rendering (false);
auto render = [&rendering, &display, &signal] (void)
{
while (not rendering)
{std::this_thread::yield ();};
do {display.draw (signal);}
while (display.rendering ()); // returns false when user quits
rendering = false;
};
auto capture = [&rendering, &daq] (void)
{
for (int i = daq.read_frequency (); i --> 0;)
daq.record (); // fill the buffer before displaying the signal
rendering = true;
do {daq.record ();}
while (rendering);
daq.stop ();
};
std::thread rendering_thread (render);
std::thread capturing_thread (capture);

rendering_thread.join ();
capturing_thread.join ();

有时这会很好用,但通常我会口吃得很厉害。我让 render ()capture () 在每次循环迭代时打印一行,然后给这些行上色,使红色来自 render () 而蓝色来自 capture ():

thread execution vs time

左图来自平稳运行,右图来自卡顿运行。

我使用 openMP 在 C 中编写了大致等效的程序,并且性能始终很流畅:

int status = 0;
#pragma omp parallel num_threads(2) private(tid) shared(status)
/* READ AND DRAW */ {
tid = omp_get_thread_num ();
/* DRAW */ if (tid is 0) {
int finished = 0;
while (not finished) {
#pragma omp critical
/* GET JOB STATUS */ {
finished = status;
}
finished = renderDisplay ();
}
#pragma omp critical
/* TERMINATE DISPLAY */ {
cvDestroyAllWindows();
}
#pragma omp atomic
status ++;
#pragma omp flush(status)
}
/* READ */ if (tid is 1) {
int finished = 0;
while (not finished) {
#pragma omp critical
/* GET JOB STATUS */ {
finished = status;
}
captureSignal ();
}
}
#pragma omp barrier
}

至少,C 和 C++11 版本看起来都和我一样,但我不明白为什么 C++11 版本会出现卡顿现象。

我无法发布 SSCCE,因为 daq.* 例程都依赖于 NI DAQ 库,但可能值得注意的是 daq.record ()阻塞直到物理设备完成读取,并且 NI DAQ 库本身在启动时产生多个线程。

我已经尝试在各种配置中实现原子标志并更改函数调用顺序,但似乎没有任何效果。

这是怎么回事,我该如何控制它?

更新:增加 DAQ 的采样率可以缓解这个问题,这让我强烈怀疑这确实与 daq.record () 是一个事实有关阻止调用。

最佳答案

正如评论中的人所提到的,您对日程安排没有太多控制权。可能对您更有帮助的是远离自旋锁和使用条件。如果渲染线程运行得太快并处理了捕获线程生成的所有数据,这将强制使渲染线程进入休眠状态。你可以看看this example进行 1 次迭代。在您的情况下,每次捕获线程提供更多数据时,您都需要调用 notify_one()。您可以使用 wait 的版本对于您的情况,只需要 1 个参数。

所以你的代码会变成这样

std::mutex mutex;
std::condition_variable condition;
std::atomic <bool> rendering (false);
auto render = [&rendering, &display, &signal] (void)
{
// this while loop is not needed anymore because
// we will wait for a signal before doing any drawing
while (not rendering)
{std::this_thread::yield ();};
// first we lock. destructor will unlock for us
std::unique_lock<std::mutex> lock(mutex);
do {
// this will wait until we have been signaled
condition.wait(lock);
// maybe check display.rendering() and exit (depending on your req.)
// process all data available
display.draw (signal);
} while (display.rendering ()); // returns false when user quits
rendering = false;
};
auto capture = [&rendering, &daq] (void)
{
for (int i = daq.read_frequency (); i --> 0;)
daq.record (); // fill the buffer before displaying the signal
rendering = true;
condition.notify_one();
// special note; you can call notify_one() here with
// the mutex lock not acquired.
do {daq.record (); condition.notify_one();}
while (rendering);
daq.stop ();
// signal one more time as the render thread could have
// been in "wait()" call
condition.notify_one();
};
std::thread rendering_thread (render);
std::thread capturing_thread (capture);

rendering_thread.join ();
capturing_thread.join ();

这样做也会消耗更少的 CPU 资源,因为渲染线程会在没有数据要处理时进入休眠状态。

关于c++ - 为什么我的线程有时会出现 "stutter"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22607377/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com