Я пытаюсь написать многопоточный код для чтения с 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 ()
:
Левый участок - от плавного хода, правый участок - от пробега с заиканием.
У меня была примерно эквивалентная программа на C с использованием openMP, и производительность всегда была гладкой:
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 и С++ 11 выглядят эквивалентно мне, но я не могу понять, почему заикание происходит в версии С++ 11.
Я не могу опубликовать SSCCE, потому что все подпрограммы daq.*
зависят от библиотеки NI DAQ, но, возможно, стоит отметить, что daq.record ()
блокируется, пока физическое устройство не закончит чтение, и сама библиотека NI DAQ libwns несколько потоков при запуске.
Я попытался реализовать атомные флаги в различных конфигурациях и сменить порядок вызова функций, и ничто, кажется, не имеет эффекта.
Что здесь происходит, и как я могу его контролировать?
update: увеличение частоты выборки DAQ облегчает проблему, что приводит меня к серьезному подозрению, что это имеет какое-то отношение к тому, что daq.record ()
является блокирующим вызовом.