C++ async makes program unresponsive - c++

I'm currently trying to create a C++ wrapper for my program to use GStreamer.
So I have created a Class "Audio" with a method "play" that starts a stream. Because of the call to g_main_loop_run inside it, it won't return until the main loop quits.
I dont want that behaviour and thus I'm trying to make an async call to another method within the play method, which would then start the main loop and allow the play method to return.
It currently looks like this:
void play(const char* uri) {
stop();
if (uri) {
g_object_set(G_OBJECT(pipeline), "uri", uri, NULL);
} else {
cout << "Please specify an URI you wish to play" << endl;
return;
}
gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING);
auto handle = async( launch::async, &Audio::playAsync, this, uri);
}
void playAsync(const char* uri) {
cout << "playing async" << endl;
g_main_loop_run(this->getLoop());
}
But the result is that the program is getting unresponsive... the playAsync method is called (its printing the cout), and playback starts and continues to play, but the GUI becomes totally unresponsive and can only be quit by killing the program.
Do you have any help for me?
regards, tagelicht

Async returns future and future must be finished (it waits for the result) when it goes out of scope.
It's exactly the same as using just async(...); as handle goes out of scope just after assigment.

Related

Starting/stopping function using QT GUI buttons

I am writing a simple Qt C++ GUI window for the user to input certain values for a USRP device to record (i.e. input start frequency, stop frequency, etc..). Once the user inputted the values, the "EXECUTE" button is clicked and the execute_run_usrp() function is called in its own thread (so not to block the GUI). Then the STOP button should be able to be clicked at any time to terminate the thread running the function that runs the USRP, execute_run_usrp(), thus terminating the USRP recording process.
The function run_usrp(x,y,z,etc) is defined in another *.cpp file in the Project.
The problem that I am having that the STOP button when clicked only seems to "pause" the function...doesn't actually kill it (like with CTRL-C, which works great here)
Here is my code from MainWindow.cpp for the EXECUTE button click:
// run the following when EXECUTE button is clicked
void MainWindow::on_button_EXECUTE_clicked()
{
if ( ui->calculated_StartTime->text() == "" )
{
QMessageBox messageBox;
messageBox.critical(0,"Error","Hit the \"CALCULATE SCHEDULE\" button first above!!");
messageBox.setFixedSize(500,200);
return;
}
ui->button_STOP->setVisible(true);
ui->button_EXECUTE->setVisible(false);
auto function = std::bind([this]{execute_run_usrp();});
QThread* temp = QThread::create(function);
temp->start();
connect( ui->button_STOP, SIGNAL(clicked()), temp, SLOT( terminate() ));
}
Here is the execute_run_usrp() function:
void MainWindow::execute_run_usrp()
{
float startFreq = ui->input_startFreq->text().toFloat();
float stopFreq = ui->input_stopFreq->text().toFloat();
float stepFreq = ui->input_stepFreq->text().toFloat();
int nRepeats = ui->input_numRepeats->text().toInt();
float ipp = ui->input_IPP->text().toFloat();
int sweepCadence = ui->calculated_sweepCadence->text().toInt();
int numSweeps = ui->input_numSweeps->text().toInt();
std::string schedule_run = ui->calculated_StartTime->text().toStdString();
std::cout << startFreq << std::endl;
std::cout << stopFreq << std::endl;
std::cout << stepFreq<< std::endl;
std::cout << nRepeats << std::endl;
std::cout << ipp << std::endl;
std::cout << sweepCadence << std::endl;
std::cout << numSweeps << std::endl;
run_usrp(startFreq, stopFreq, stepFreq, nRepeats, ipp, sweepCadence, numSweeps, schedule_run);
}
And here is the STOP button code:
void MainWindow::on_button_STOP_clicked()
{
ui->button_STOP->setVisible(false);
ui->button_EXECUTE->setVisible(true);
}
Clicking the STOP button only seems to pause the function, doesn't actually kill it like doing CTRL-C with the keyboard. I think the UHD library (that runs the USRPs) spwans its own thread for running.
Question: How do I 100% terminate the entire function (and including any spwaned children from UHD) when I hit the STOP button ?
Thank you very much!
How do I 100% terminate the entire function (and including any spwaned children from UHD) when I hit the STOP button ?
From the code you've shown there's no easy answer imho.
The shortest one is: by incorporating some inter-thread communication inside the USRP function, provided you want some sort of graceful exit.
As for terminate, QT's docs state:
This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.
Alternatively, the whole USRP function can be run inside a separate process, that is then killed. Again, plain killing of the process is far from graceful, still it seems easier and safer than doing it to a thread. You may want to check QProcess for reference.

Sleep inside QTConcurrent run method

I'm using QtConcurrent::run to execute some functions in background and not hang the GUI thread. In one function, I read logs from local SQlite database and send them to server by TCP socket.
Now I want to delay the execution after each log so the server has time to save it (TCP response is read in different thread). I'm stuck with Qt4.8 due to implementation limitations (many embeded devices - no chance to upgrade QT on them) and I can't use QThread::sleep(2) because it is protected in 4.8.
Is it possible to somehow pause the execution of thread inside QtConcurrent::run method or should I redesign it to implement my own class inheriting QThread?
void MainWindow::ReportFinishedHUs(bool asyncWork)
{
if(asyncWork == false)
{
QMutexLocker locker(&localDBmutex);
QList<QSqlRecord> HUsToReport = localDB->getHUsForBook();
qDebug() << "HUs to report" << HUsToReport.count();
if(!HUsToReport.isEmpty())
{
Cls_log::WriteDebugLog("HUs to report: " + QString::number(HUsToReport.count()));
foreach (QSqlRecord record, HUsToReport)
{
int _hu = record.indexOf("hu");
int _logTime = record.indexOf("logTime");
QString logTimeString = record.value(_logTime).toString();
QString hu = record.value(_hu).toString();
qDebug() << hu << logTimeString;
// creating message here ...
qDebug() << message;
emit sig_SendTCPMessage(message);
// this is where I need to wait for 2 seconds
QThread::sleep(2);
}
}
}
else
{
QtConcurrent::run(this, &MainWindow::ReportFinishedHUs, false);
}
}
EDIT:
Solved by usleep(2000000) which I somehow discarded for being platform specific... but hey, half of my aplication is platform specific and I only use it in embeded device with constant OS.
Keeping the question open if anyone can suggest more elegand solution using Qt methods. I like to get inspired.

Threading issue where 1 thread works but causes the calling method to not return

I am currently learning C++ and I am having an odd issue with threads. I've done lots of threaded stuff in Java and C# and not had an issue. I am currently trying to replicate a C# library that I have in C++ with a library and a test app.
In main.cpp I create an instance of a InitialiseLibrary class and call the method initialise. This does config loading and is then supposed to start a thread which stays running through the duration the application is running. I am expecting this thread to start, and then my initialise function returns true where I then continue and I create an instance of a test class which writes to a log file every 1 second.
Below is main.cpp
InitialiseLibrary initLibrary("config.ini");
if (!initLibrary.initialise(1))
{
cout << "Failed to initialise library" << endl;
return EXIT_FAILURE;
}
TestClass testClass;
testClass.writeSomeLogsInThread();
cout << "The library config log file is: " << GlobalConfig::GeneralConfig::logFile << endl;
In my Initialise method (which is in the library) I have:
bool InitialiseLibrary::initialise(int applicationAlarmID, int applicationTerminationTimeout)
{
//statusManager.setApplicationStatus(StatusManager::ApplicationStatus::Starting);
if (!this->loadInconfiguration(applicationAlarmID))
{
cout << "*****Failed to configuration. Cannot continue******" << endl;
return false;
}
GlobalConfig::libraryInitialised = true;
LogRotation logRotation;
logRotation.startLogRotation();
BitsLibrary bitsLibrary;
//Set up the signal handler if its needed, 0 means it terminates instantly, doesn't wait -1 is don't use signal handler
if (applicationTerminationTimeout >= 0)
{
bitsLibrary.setupSignalHandler(applicationTerminationTimeout);
}
return true;
}
As you can see, I read in the configuration and I then call `logRotation.startLogRotation().
Where I have the following code:
void LogRotation::startLogRotation()
{
//Is the configuration successfully loaded
if (!LogRotateConfiguration::configurationLoaded)
{
throw exception("Log Rotation not initialised");
}
BitsLibrary bitsLibrary;
stringstream logStream;
logStream << "Log rotation thread starting, monitor cycle time is " << LogRotateConfiguration::archiveSleepTimeInSeconds << " second(s)";
bitsLibrary.writeToLog(logStream.str(), "LogRotation", "startLogRotation");
thread logRotationThread(&LogRotation::logRotationThread, this);
logRotationThread.join();
}
void LogRotation::logRotationThread()
{
BitsLibrary bitsLibrary;
while (bitsLibrary.getApplicationStatus() == StatusManager::ApplicationStatus::Starting || bitsLibrary.getApplicationStatus() == StatusManager::ApplicationStatus::Running)
{
bitsLibrary.writeToLog("Running log monitoring");
this_thread::sleep_for(chrono::seconds(LogRotateConfiguration::archiveSleepTimeInSeconds));
}
stringstream logStream;
logStream << "Log rotation archive monitoring stopped. Current application status: " << bitsLibrary.getApplicationStatus();
bitsLibrary.writeToLog(logStream.str(), "LogRotation", "logRotationThread");
}
Here I am expecting, startLogRotation() to start run the method logRotationThread within a thread, the thread starts, and the startLogrotation() method finishes and backs through the stack to the initialise() method where that returns true, back up to main where I can then call my TestClass method within a thread.
For some reason though, the thread starts and keeps logging every few seconds Running log monitoring so I know the thread has started, yet it doesn't seem to return back to the initialise function to return true, so the app gets stuck on that function call and doesn't go any further.
I've read that you need to run join on the thread to keep it in sync with the main thread, otherwise the main thread exits, while the new threads are running and cause a SIGABRT which in deed it does, but having the join there seems to stop the method returning.
join waits for a thread to finish executing, so when you join, startLogRotation won't return until that happens.
Also, the normal rules of scope and lifetime apply to thread objects - logRotationThread will be destroyed when startLogRotation returns.
If the thread is "joinable" at the time of destruction, it's an error.
The simplest solution is probably to have a LogRotation member in InitialiseLibrary and a thread member in LogRotation.
You can then join the thread in LogRotation's destructor.
Your main thread blocks at this line, waiting for the logRotationThread to end.
logRotationThread.join();
Your main thread should go and do whatever work it needs to do after spawning the other thread, then only when it has nothing left to do should it join() the log rotate thread.
"having an odd issue with threads" - welcome to the world of threading!
I think you mis-understand the stack of the thread you create, and how it will interact with the main thread. The created thread's stack starts at the function you tell it to start with - when that function completes, the thread dies (which will then allow your join() to stop blocking)
With regards to your communication between threads, I think you should have a read about mutex's, conditions and semaphores.
From what I can tell,
logRotationThread is a long running thread (it runs for the entire duration of the application). There is no need for the main thread to ever wait (join) on the logRotationThread.
For starters remove logRotationThread.join().

double Gtk::Messadialog before quitting

I'm trying to display a message dialog if the pid of running program is valid, This is my essencial code:
Gtk::Main kit (argc, argv);
Glib::RefPtr<Gtk::Builder> refBuilder = Gtk::Builder::create();
try { refBuilder->add_from_file (UI_PATH); }
catch (const Glib::FileError& ex) {
std::cout << "FileError: " << ex.what() << std::endl;
return 1;
}
catch (const Gtk::BuilderError& ex) {
std::cout << "BuilderError: " << ex.what() << std::endl;
return 1;
}
FormUI * ui = 0;
refBuilder->get_widget_derived ("window1", ui);
if (ui) {
kit.run (*ui);
}
delete ui;
Constructor:
signal_delete_event ().connect (sigc::mem_fun (*this, &FormUI::on_delete_event));
method:
bool FormUI::on_delete_event (GdkEventAny* event) {
if (_pid) {
bool retState;
Gtk::MessageDialog md(*this, Glib::ustring::compose ("<b>%1</b>", _("Warning: youtube-dl in process")), true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
md.set_title (PACKAGE_STRING);
md.set_secondary_text (_("Closing can generate a corrupted file, do you want to continue anyway?"));
if (md.run() == Gtk::RESPONSE_YES) {
kill (_pid, 0);
retState = false;
} else {
retState = true;
}
md.hide ();
return retState;
}
return false;
}
With the above, if pid is valid it displays the messagedialog as expected, but if I hit "yes" (to exit the application) it displays another messagedialog..why?
You said that FormUI is derived from Gtk::Window. Gtk::Window has a virtual method on_delete_event() that is automatically connected to the delete-event signal, no questions asked. Oops, you implemented a virtual method without knowing it! So what you did by calling
signal_delete_event ().connect (sigc::mem_fun (*this, &FormUI::on_delete_event));
was unknowingly connect that signal twice, and because Gtk::Window::on_delete_event() is virtual, both connections go to your own method.
Okay, so why do we still get two dialog boxes? Doesn't returning false mean to close the window? Not really.
delete-event is a GDK event. GDK events always return a boolean value: if the value is false (GDK_EVENT_PROPAGATE), the next signal handler in the signal connection chain is run, and if the return value is true (GDK_EVENT_STOP), no further signal in the signal connection chain is run.
It just so happens that if you don't stop a delete-event from propagating through the signal connection chain, the window is destroyed. So when there was only one handler connected, returning false from that handler would effectively destroy the window.
But now you have two handlers connected. The first one will return false, which causes the second one to run, and you get your second message dialog. When that one returns false, you get your window being destroyed.
Hopefully that should explain this problem. You can solve this by either not calling signal_delete_event().connect() or by changing the method name to something else. Be sure to watch the gtkmm documentation to make sure you aren't accidentally using other virtual methods that are automatically connected to signals (I'm not sure why gtkmm provides these virtual methods; convenience?). And be sure to understand how GDK events work; you'll need to know this if you ever play with GDK events for real (such as handling input in a Gtk::DrawingArea).

ALSA re-enter to callback during callback execution

My application uses ALSA with callbacks facility to play selected piece of sound. Sometimes it just hangs. I was debugging it hardly 2 days, and finally found that ALSA's callback function invoked while it is executing already. I caught this using:
void MyALSACallback()
{
std::cout << "1"; std::cout.flush();
// ... snd_pcm_writei() call ... //
// ... no any returns ... //
std::cout << "2"; std::cout.flush();
return;
}
The application hangs when i have sequence "11" printed. The "121212..." is on console while application is alive and sound is playing.
How that may happen?