PDA

View Full Version : Console Application cannot stop properly a thread



erakis
5th December 2014, 04:30
Hi,

I would like to create a thread that is polling a serial port continuously. The application will be a deamon or a service (according the platform). But for now I'm developing using a Console application on Windows because it is more easy to debug.

The idea should be to create a thread and this thread will run forever or until the console application is closed. But just before the console closed itself it should wait until the thread finished. Thus, the console application should signal to the thread to stop. The main loop of the thread could poll a boolean or an event for that. This is what I call closing an application properly.

Now, I read a lot of documentation of QT Reference, Google, etc... But I never get this working *properly*.

Once I click on the X button of the console, or pressing key CTRL+C, the application close itself without having chance to signal to the thread to stop. How can I free resource used by the thread before it stop ? Worst, I'm asking to myself how the thread is stop ? Does it stop because it parent process has been killed ? If yes, this can lead to memory leak.

Here is what I've done (test code, forget about scope, bad design please or deriving class from QThread):


#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <csignal>

class WorkerThread : public QThread
{
public:
explicit WorkerThread (QObject *parent = 0)
:m_bStopThread(false) { }

private:
void run()
{
// Thread run forever or until m_bStopThread = true
while (!m_bStopThread)
{
qDebug() << "Worker thread operation... " << currentThreadId();
QThread::msleep(1000);
}
return; // This breakpoint will never be triggered once the application is stop using X button of the windows or CTRL+C keyboard keys.
}
public :
volatile bool m_bStopThread;

public Q_SLOTS:

void aboutToQuitApp()
{
m_bStopThread = true; // This breakpoint will never be triggered once the application is stop using X button of the windows or CTRL+C keyboard keys.
}
};

// This struct is a tips that I get from a forum that is supposed to catch the application closing. But it does not really work at all.
struct CleanExit
{
static WorkerThread* pWorkerThread;

CleanExit(WorkerThread* _pWorkerThread)
{
CleanExit::pWorkerThread = _pWorkerThread;

signal(SIGINT, &CleanExit::exitQt);
signal(SIGTERM, &CleanExit::exitQt);
signal(SIGBREAK, &CleanExit::exitQt) ;
}

static void exitQt(int sig)
{
// This breakpoint will be triggered only while using CTRL+C to close the application.
// But the debugger loses his way as soon as I step further...
// It is as if the application was already being closed and that I have no control on the
// worker thread. The system has kill the thread because its parent process has been killed.
pWorkerThread->m_bStopThread = true;
pWorkerThread->wait();

QCoreApplication::exit(0);
}
};
WorkerThread* CleanExit::pWorkerThread = NULL;

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

WorkerThread wk;
CleanExit cleanExit(&wk);

QObject::connect(&wk, SIGNAL(finished()), &a, SLOT(quit()));

// The signal aboutToQuit does not seem to work using Console Application.
QObject::connect(&a, SIGNAL(aboutToQuit()), &wk, SLOT(aboutToQuitApp()));

qDebug() <<"Starting worker thread ..." << QThread::currentThreadId();
wk.start();

// Wait until the worker thread has finished his work !
wk.wait();

// Close the console application
return a.quit();
}

Just read the comments, all my questions/problem are here.

Best regards,

anda_skoa
5th December 2014, 07:23
Well, aside from the obvious question why you need a thread in the first place and the also unavoidable hint that you have a race condition:

the operating system will free all memory allocated to you process and it will terminate the thread.
It might not be able to do any specific cleanup though.

Have you tried not installing your own signal handler but stopping the thread after QCoreApplication::exec() has returned?

Cheers,
_

erakis
5th December 2014, 13:05
First, thank for you quick anwser :)

I am relatively novice with Qt and as I read on the QT Reference, the main loop (the code executed in the exec of the QCoreApplication) handle message pump. If I am not using any thread and I am doing a while (bStop) in the main, the QCoreApplication will never have the opportunity to handle any message ? Thus, how the closing event will be detected ? In addition, if (to handle event) I must called "ProcessEvent", this will slow down the operation of my serial port that are time crucial. Maybe you have a better solution ?

What do you mean by "race condition" ? If the console application would received a "CLOSING" event, I could signal to my thread to :

Stop
Clean resources properly
Call "join" on this thread from the main thread to wait until the thread is properly stopped
Finally, letting the console application close


I've done this a lot of time on Windows Win32/MFC and it is well working and I think it is the way to go for this kind of job. But now I have to use QT as this application will be deamon/service and could be use either on Windows or Linux.


the operating system will free all memory allocated to you process and it will terminate the thread.
Yes, I am aware of that but the OS will only MEMORY but it will not free other kind of resource/condition in consideration.


Have you tried not installing your own signal handler but stopping the thread after QCoreApplication::exec() has returned?
Could you help me with that ? Some example code would be appreciated please.

Best regards,

anda_skoa
5th December 2014, 15:38
I am relatively novice with Qt and as I read on the QT Reference, the main loop (the code executed in the exec of the QCoreApplication) handle message pump. If I am not using any thread and I am doing a while (bStop) in the main, the QCoreApplication will never have the opportunity to handle any message ?

Yes


Thus, how the closing event will be detected ? In addition, if (to handle event) I must called "ProcessEvent", this will slow down the operation of my serial port that are time crucial. Maybe you have a better solution ?

I am mostly asking because I/O is Qt is usually done event driven, e.g. sockets, but also serial port.
So I was wondering if you are sure you'll need a thread and all the things that come with multithreaded programming.



What do you mean by "race condition" ?

In multithread programming that refers to access to a shared resource, e.g. memory, by two threads without the necessary synchronization.
Also called a data race.
In your case one thread writing a variable and the other reading it.



If the console application would received a "CLOSING" event

This usually means that the Qt installed signal handler exits the main event loop.

Have you tried with a simple program without any thread?
Just a QCoreApplication that execs and print something after the exec call?

Cheers,
_

erakis
10th December 2014, 14:38
Hi,



So I was wondering if you are sure you'll need a thread and all the things that come with multithreaded programming.We need a Thread because we have use the QSerialPort class using event driven but it is not as fast as sync way. And the way it is implemented (using event driven) causes us implementation issue for our custom protocol.


In multithread programming that refers to access to a shared resource, e.g. memory...
Yes I exactly know what is a "race condition" ;) But I was asking WHY you said that ? The variable m_bStopThread is mark as VOLATILE to avoid cache reading. And don't forget that this example code was keep short to understand. In production I would use a mutext to protect those variables. Even if there was a race condition (in this context example), this would not prevent the closing detection mechanism of the application to stop the thread.


Have you tried with a simple program without any thread
Yes, with a single while (s_bStopThread) in the main and having the s_bStopThead be STATIC variable. Same probleme, no breakpoint hits, no printf in release mode. This do not work.

What I've read on the subject is that SIGNAL handler are called from an external thread own by the OS. So when this thread is trying to change our local variable (s_bStopThread), this crash or do nothing as they are not hosted on the same process. As a workaround we could use a kind of process shared memory to signal to the main application to stop the thread before returning from the signal handler. Here is a link to a way to do that (LINUX only) : https://qt-project.org/doc/qt-4.7/unix-signals.html. I've run this example on Linux and when I'm using CTRL+C the program does NOTHING. Thus, What I conclude is that it does not work :( I've also implemented this example for Windows (using PIPE and UPD socket) but this is SIMPLY NOT WORKING too.

Database server are often implemented as a service or daemon and are build using a a console application as we are trying to do now. Sure they use one or many thread internally. How they stop their thread properly while getting a SIGTERM ? If they do not do it and kill the application, say it the middle of creating a table... there would corrupt the database! I don't talk about getting the power off on the computer by pulling the cable but rather stopping the deamon or service using an interface or CTRL+C.

Best regards,

anda_skoa
10th December 2014, 15:44
We need a Thread because we have use the QSerialPort class using event driven but it is not as fast as sync way. And the way it is implemented (using event driven) causes us implementation issue for our custom protocol.

Ah, I see.
One thing you should still try is to use event driven QSerialPort but in its own thread.
I.e. making sure the serial thread only has to process serial e



Yes I exactly know what is a "race condition" ;) But I was asking WHY you said that ? The variable m_bStopThread is mark as VOLATILE to avoid cache reading.

Nope. That keyword prevents the compiler from optimzing access to the variable.

The only way to achieve lock-free value exchange is to use atomics, e.g. QAtomicInt



And don't forget that this example code was keep short to understand. In production I would use a mutext to protect those variables

The problem seems to be synchronisation between two threads, so threading issues need to be taken into account.
An example is only good when it is accurate.


Even if there was a race condition (in this context example), this would not prevent the closing detection mechanism of the application to stop the thread.

How so?
If the value never reaches the second thread, how would it know to stop?



What I've read on the subject is that SIGNAL handler are called from an external thread own by the OS. So when this thread is trying to change our local variable (s_bStopThread), this crash or do nothing as they are not hosted on the same process. As a workaround we could use a kind of process shared memory to signal to the main application to stop the thread before returning from the signal handler. Here is a link to a way to do that (LINUX only) : https://qt-project.org/doc/qt-4.7/unix-signals.html. I've run this example on Linux and when I'm using CTRL+C the program does NOTHING. Thus, What I conclude is that it does not work :( I've also implemented this example for Windows (using PIPE and UPD socket) but this is SIMPLY NOT WORKING too.


I'll have to try that myself. Should have time for that tomorrow, hopefully.

Cheers,
_

erakis
10th December 2014, 15:59
Hi anda :)

We are shot in time but we don't have any other solution so sure, give a try when you'll have free time :) It will be appreciated.


If the value never reaches the second thread, how would it know to stop?I did tried using mutext, do you agree with me that the condition (variable) would be protected. The thread ONLY read the variable and do not change its value. The only thread changing the value of the variable is the external thread for the signal handler.

By the way, "OPTIMIZING" accesss for volatile keyword was a better definition than mine, thanks. But the idea was to explain you that I care about the variable shared access between the threads. Only ONE writter single writter so even if we were using an ATOMIC way, mutex, or any other sync method, the example should work anyway in this case.

Best regards,

anda_skoa
11th December 2014, 14:18
This works for me (on Linux)


#include <QtCore>

#include <signal.h>

class Thread : public QThread
{
public:
explicit Thread(QSemaphore &s, int id, QObject *parent = 0)
: QThread(parent)
, m_semaphore(s)
, m_id(id)
, m_stop(false)
{
}

void stop()
{
QMutexLocker locker(&m_mutex);
m_stop = true;
}

void run()
{
qDebug() << "Starting secondardy thread" << m_id;

while(!shouldStop()) {
msleep(10);
}

qDebug() << "Secondary thread" << m_id << "exiting";
m_semaphore.release();
}

private:
mutable QMutex m_mutex;
QSemaphore &m_semaphore;
int m_id;
bool m_stop;

private:
bool shouldStop() const
{
QMutexLocker locker(&m_mutex);
return m_stop;
}
};

void signalHandler(int signalNumber)
{
qDebug() << Q_FUNC_INFO << signalNumber;

QMetaObject::invokeMethod(QCoreApplication::instan ce(), "quit", Qt::QueuedConnection);
}

int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);

signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);

QSemaphore semaphore(0);

QVector<Thread*> threads(10);
for (int i = 0; i < threads.count(); ++i) {
threads[i] = new Thread(semaphore, i);
threads[i]->start();
}

qDebug() << "Starting Main thread event loop";
int ret = app.exec();

for (int i = 0; i < threads.count(); ++i) {
threads[i]->stop();
}
semaphore.acquire(threads.count());

qDeleteAll(threads);

qDebug() << "Main thread exiting";
return ret;
}


Cheers,
_

Lesiok
11th December 2014, 14:57
Also works under Windows.

erakis
18th December 2014, 15:20
Hi all,

Sanda, I've tried your sample code but there is something that I still not understand or maybe this solution still does not work :(

On Windows I have added this small code part, just after releasing the semaphore :

qDeleteAll(threads);

QFile file("C:\\qtThreadEnded.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << "Application closing PROPERLY !!!\n";
file.flush();
file.close();

Simply to write a file when the application exit. Here is the way I've test :

Task Manager [End Task]

I open the task manager, I click on the console process line and then I click on "End Task" menu. Usually the WM_CLOSE is send but as we are in a console application, no windows will handle this message ? But, is Windows smart enough to send a SIGTERM instead ? Anyway the application is closing and I can confirm you is that NO file has been written C:\\qtThreadEnded.txt.

X button of console Window

I've read somewhere that End Task and clicking the X Button of the console Application do the same kind of kill on Windows. The application is closing but Still NO file has been written C:\\qtThreadEnded.txt.

CTRL+C

The break point set in the signalHandler is hit, good news ! But application is not closing and still NO file has been written C:\\qtThreadEnded.txt.



The fact that no file is written is indicating us that process is not exited as we WANT. The process is not waiting for thread to be stop, cleaning resource and stop process. Instead, the OS process closes abruptly the process.

I have not tried on Linux, this is my next step.
However, I want to thank you again for your help is much appreciated :)

Best regards,

anda_skoa
18th December 2014, 17:00
Since your target is a service, have you tried whatever shutdown method Windows uses for that?
I.e. the equivalent to SIGTERM on Linux?

As for the WM message, you could try with a native event filter in the application's event dispatcher and call quit() when this message arrives.

As for the file: verify that you can actually write that file, e.g. write to it at the startup.

I am afraid I don't know enough about process behavior on Windows, for all I know the things you are currently trying are equivalent to SIGKILL :)

Cheers,
_

erakis
18th December 2014, 17:26
Before posting the preceding message I have already tried to write the file at the application startup and the file has been successfully written. So this is not the problem :(

How can I intercept the message WM_CLOSE using event dispatcher ? Could you give me information ?

I think Windows is using another mechanism for controller services.
Ref : http://msdn.microsoft.com/en-us/library/windows/desktop/ms683240(v=vs.85).aspx
But after reading on that, it seams to be very similar to POSIX signal.

Also, I'm asking to myself on Windows if using "signal" function is not the right way ? Here is another information about signal handling on windows. Maybe using the "SetConsoleCtrlHandler" function will produce the same problem but I will give a try.
Ref : http://msdn.microsoft.com/en-us/library/ms686016%28VS.85%29.aspx
Ref : http://stackoverflow.com/questions/7404163/windows-handling-ctrlc-in-different-thread
Ref : http://stackoverflow.com/questions/8698881/intercept-wm-close-for-cleanup-operations

I have not time yet to test on Linux but if you press CTRL+C, you confirmed that application is PROPERLY shutdown ?

anda_skoa
18th December 2014, 18:58
How can I intercept the message WM_CLOSE using event dispatcher ? Could you give me information ?

Each Qt event loop, e.g. the one of running QCoreApplication::exec(), is based on an implementation of QAbstractEventDispatcher.
It passes all events it gets from whatever native event system it is based on to a chain of event filters.

An application can install its own native event filter, see https://qt-project.org/doc/qt-5-snapshot/qabstracteventdispatcher.html#installNativeEventFi lter

Assuming this WM_CLOSE you mentioned earlier is some form of Windows native event, it should be detectable by your filter.


I have not time yet to test on Linux but if you press CTRL+C, you confirmed that application is PROPERLY shutdown ?

Yes. Also worked with kill -INT and kill -TERM

For example with CTRL+C it looks like this


./threadexittest
Starting Main thread event loop
Starting secondardy thread 7
Starting secondardy thread 3
Starting secondardy thread 0
Starting secondardy thread 1
Starting secondardy thread 2
Starting secondardy thread 8
Starting secondardy thread 5
Starting secondardy thread 9
Starting secondardy thread 6
Starting secondardy thread 4
^Cvoid signalHandler(int) 2
Secondary thread 1 exiting
Secondary thread 5 exiting
Secondary thread 9 exiting
Secondary thread 7 exiting
Secondary thread 6 exiting
Secondary thread 3 exiting
Secondary thread 4 exiting
Secondary thread 8 exiting
Secondary thread 0 exiting
Secondary thread 2 exiting
Main thread exiting


Cheers,
_

erakis
22nd December 2014, 16:18
I confirm that it is well working on Linux (Ubuntu) using CTRL+C but ONLY while lunching it from a shell.
Doing the same thing using the QtCreator debugger only throw an EXCEPTION and nothing happen except breaking on the a.exec() line. If we click on CONTINUE command of the debugger, the process simply continue without stopping... weird !

For Windows : I'll try the other stuff I mentioned in the previous post and I will come back here for conclusion.

wysota
23rd December 2014, 07:39
I confirm that it is well working on Linux (Ubuntu) using CTRL+C but ONLY while lunching it from a shell.
Doing the same thing using the QtCreator debugger only throw an EXCEPTION and nothing happen except breaking on the a.exec() line. If we click on CONTINUE command of the debugger, the process simply continue without stopping... weird!
That is perfectly normal, the debugger is intercepting the signal. Run the application without a debugger and it will behave as expected.

yeye_olive
23rd December 2014, 11:06
This might be coming a bit late, but I can confirm that SetConsoleCtrlHandler() definitely is the way to go. I have used it several times. I once wrote an OS-independent abstraction of a "termination handler" that would emit a Qt signal when receiving a termination request from the OS. The implementation for Windows console applications used SetConsoleCtrlHandler() and the design was roughly along these lines (but with some hiding of the internal structures):


class Handler : public QObject {
Q_OBJECT
signals:
void terminated();
public:
void emitTerminated() {
emit terminated();
}
};

QMutex mutex;
Handler *handler = NULL;

BOOL WINAPI winHandler(DWORD /*dwCtrlType*/) {
QMutexLocker lock(&mutex);
if (handler == NULL)
return FALSE;
handler->emitTerminated();
return TRUE;
}

void registerHandler() {
QMutexLocker lock(&mutex);
assert(handler == NULL);
handler = new Handler;
SetConsoleCtrlHandler(winHandler, TRUE);
}

void unregisterHandler() {
QMutexLocker lock(&mutex);
handler->deleteLater();
handler = NULL;
SetConsoleCtrlHandler(winHandler, FALSE);
}

You can then connect to the Handler::terminated() signal to be notified of the termination request.

anda_skoa
23rd December 2014, 12:05
You can then connect to the Handler::terminated() signal to be notified of the termination request.
The QMetaObject::invokeMethod() should work in this case as well, i.e. inside winHandler(), without the need for global variables

Cheers,
_

yeye_olive
23rd December 2014, 13:10
The QMetaObject::invokeMethod() should work in this case as well, i.e. inside winHandler(), without the need for global variables
I do not understand what you mean. The first argument of the QMetaObject::invokeMethod() call would still need to be stored in a global variable. In any case, there is no absolute need for the Handler class; one may invoke a slot on QCoreApplication::instance(), etc. Emitting a signal and letting the user decide who to connect it to just makes the design more modular (although evertything should be encapsulated and hidden behind a nicer interface). Besides, the mutex and the check (handler == NULL) are needed in case the user unregisters the handler when winHandler is about to run.

anda_skoa
23rd December 2014, 13:23
The first argument of the QMetaObject::invokeMethod() call would still need to be stored in a global variable.

Not in the case of quitting the application.



Besides, the mutex and the check (handler == NULL) are needed in case the user unregisters the handler when winHandler is about to run.

The Qt::QueuedConnection takes care of the thread crossing by sending the method invocation request as an event to the receiver object's thread event loop.

Cheers,
_

yeye_olive
23rd December 2014, 13:47
Not in the case of quitting the application.
OK. This design is a bit more general in that it lets the user decide what to do with the notification.

The Qt::QueuedConnection takes care of the thread crossing by sending the method invocation request as an event to the receiver object's thread event loop.
Yes, that is why I chose to rely on Qt's thread safe signal emission. That is not why the mutex is needed. The mutex is here because the receiver object might not exist any more when winHandler runs. After unregistering the handler, I cannot tell when winHandler will definitely never be run any more. The problem would be the same with a call to QMetaObject::invokeMethod() for QCoreApplication::quit(). I would have no guarantee that winHandler would not be run after the QCoreApplication object was deallocated (which I suppose could happen if the OS queued two invocations of winHandler, then one was performed, then the application started to quit and winHandler ran again).

anda_skoa
23rd December 2014, 14:14
Well, in the case of QCoreApplication::instance() it is valid pointer until the application has be destroyed.
Which happens after the return of main().

How likely is this winHandler being called after the program has stopped?

Cheers,
_

yeye_olive
23rd December 2014, 17:29
How likely is this winHandler being called after the program has stopped?
Granted, it is highly unlikely that winHandler executes sometime between the point where the QCoreApplication instance starts being destroyed and the point the program terminates, but, as far as I can tell by reading Microsoft's documentation, nothing guarantees that it cannot happen. In fact, the documentation does not say anything about what happens after a handler has been unregistered.

Better safe than sorry.

anda_skoa
23rd December 2014, 17:42
Granted, it is highly unlikely that winHandler executes sometime between the point where the QCoreApplication instance starts being destroyed and the point the program terminates, but, as far as I can tell by reading Microsoft's documentation, nothing guarantees that it cannot happen. In fact, the documentation does not say anything about what happens after a handler has been unregistered.

Better safe than sorry.

So what makes the instance of the mutex safer than the instance of the application?

Cheers,
_

wysota
23rd December 2014, 18:57
There is a simple workaround for this chicken and egg problem - remove the handler before the application object is destroyed.

yeye_olive
23rd December 2014, 19:48
So what makes the instance of the mutex safer than the instance of the application?
Nothing, really. The mutex probably stays a little while longer since it is a global variable while the QCoreApplication is usually allocated on the stack in main(), but this does not eliminate the problem. I suppose there is no way around it, since there is no way to synchronize with the thread executing the handler, if any.

There is a simple workaround for this chicken and egg problem - remove the handler before the application object is destroyed.
How does it solve anything? Unfortunately, removing the handler does not guarantee that it will not be subsequently run, hence the need for a check in the handler.

wysota
23rd December 2014, 23:14
I don't know about Windows but in Unix there is no magic extra thread executing the handler, you can even designate a particular thread of the application to be executing a particular handler. Therefore the execution is synchronous with the flow of the program for one of the application threads therefore if no threads apart the main one outlive the application object, removing the handler before the application is destroyed makes sure the handler will not be called at any later point in time (as in after the application object dies).

yeye_olive
24th December 2014, 10:06
I don't know about Windows but in Unix there is no magic extra thread executing the handler, you can even designate a particular thread of the application to be executing a particular handler. Therefore the execution is synchronous with the flow of the program for one of the application threads therefore if no threads apart the main one outlive the application object, removing the handler before the application is destroyed makes sure the handler will not be called at any later point in time (as in after the application object dies).
Indeed, there is a solution for Unix signals. By contrast, Windows spawns a thread to execute the handler everytime the signal is received; sadly, handler unregistration offers no way to synchronize with any thread currently executing the handler being unregistered.

wysota
24th December 2014, 19:56
Indeed, there is a solution for Unix signals. By contrast, Windows spawns a thread to execute the handler everytime the signal is received; sadly, handler unregistration offers no way to synchronize with any thread currently executing the handler being unregistered.

It is enough to check in the handier whether the application object is valid before proceeding. However I am quite surprised about what you say that an extra thread is spawned - by whom? Operating system does not spawn threads for processes. The code for this would have to be generated by the compiler. I just read the docs for this function and it says nothing about any extra threads being spawned. Where did you get this information from?

yeye_olive
2nd January 2015, 23:33
It is enough to check in the handier whether the application object is valid before proceeding. However I am quite surprised about what you say that an extra thread is spawned - by whom? Operating system does not spawn threads for processes. The code for this would have to be generated by the compiler. I just read the docs for this function and it says nothing about any extra threads being spawned. Where did you get this information from?
(Sorry for the late reply. I have been offline for about a week.) I got this information from the HandlerRoutine (http://msdn.microsoft.com/en-us/library/windows/desktop/ms683242%28v=vs.85%29.aspx) page of the documentation, which is linked from the page for SetConsoleCtrlHandler (http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx); it is most unfortunate that the information be scattered around like this. The exact wording is When the signal is received, the system creates a new thread in the process to execute the function. A bit further down, a remark acknowledges the need for synchronization with the other threads of the process.