c++ - Why do my threads sometimes "stutter"? -
i trying write multithreaded code read daq device , render captured signal @ same time:
std::atomic <bool> rendering (false); auto render = [&rendering, &display, &signal] (void) { while (not rendering) {std::this_thread::yield ();}; {display.draw (signal);} while (display.rendering ()); // returns false when user quits rendering = false; }; auto capture = [&rendering, &daq] (void) { (int = daq.read_frequency (); --> 0;) daq.record (); // fill buffer before displaying signal rendering = true; {daq.record ();} while (rendering); daq.stop (); }; std::thread rendering_thread (render); std::thread capturing_thread (capture); rendering_thread.join (); capturing_thread.join ();
sometimes work fine, bad stuttering. had render ()
, capture ()
print line upon each loop iteration, , colored lines such red render ()
, blue capture ()
:
the left plot smooth run, right plot run stuttering.
i had equivalent program in c using openmp , performance smooth:
int status = 0; #pragma omp parallel num_threads(2) private(tid) shared(status) /* read , draw */ { tid = omp_get_thread_num (); /* draw */ if (tid 0) { int finished = 0; while (not finished) { #pragma omp critical /* job status */ { finished = status; } finished = renderdisplay (); } #pragma omp critical /* terminate display */ { cvdestroyallwindows(); } #pragma omp atomic status ++; #pragma omp flush(status) } /* read */ if (tid 1) { int finished = 0; while (not finished) { #pragma omp critical /* job status */ { finished = status; } capturesignal (); } } #pragma omp barrier }
at least, both c , c++11 versions look equivalent me, can't figure out why stuttering happening in c++11 version.
i can't post sscce because daq.*
routines depend on ni daq library, may worth noting daq.record ()
blocks until physical device finished reading, , ni daq lib spawns several threads when starts.
i've tried implementing atomic flags in various configurations , changing function call orders , nothing seems have effect.
what going on here, , how can control it?
update: increasing sampling rate of daq alleviates problem, leads me suspect have fact daq.record ()
blocking call.
as people in comments have mentioned don't have control of scheduling. can more turn away spin locks , use conditions. force put render thread sleep if went fast , processed data capture thread has produced. can @ this example 1 iteration. in case every time more data becomes available capture thread, need call notify_one(). can use version of wait takes 1 parameter case.
so code become this
std::mutex mutex; std::condition_variable condition; std::atomic <bool> rendering (false); auto render = [&rendering, &display, &signal] (void) { // while loop not needed anymore because // wait signal before doing drawing while (not rendering) {std::this_thread::yield ();}; // first lock. destructor unlock std::unique_lock<std::mutex> lock(mutex); { // wait until have been signaled condition.wait(lock); // maybe check display.rendering() , exit (depending on req.) // process data available display.draw (signal); } while (display.rendering ()); // returns false when user quits rendering = false; }; auto capture = [&rendering, &daq] (void) { (int = daq.read_frequency (); --> 0;) daq.record (); // fill buffer before displaying signal rendering = true; condition.notify_one(); // special note; can call notify_one() here // mutex lock not acquired. {daq.record (); condition.notify_one();} while (rendering); daq.stop (); // signal 1 more time render thread have // been in "wait()" call condition.notify_one(); }; std::thread rendering_thread (render); std::thread capturing_thread (capture); rendering_thread.join (); capturing_thread.join ();
doing way consume less cpu resources, render thread go sleep when there no data process.
Comments
Post a Comment