The case is: I register a signal handler with signal function.
The question:
Is handler always called independently of the process state? (I mean its stopped, etc.). What happens there?(dependently of the state)
Are handler functions registered as some "special functions" by system (i.e. when handeler runs other signals are not recieved and are put into the stack or smth like that. Or maybe they are simply ignored.) If not, imagine that when handler strats, process gets another signal, then this handler is called again inspite of "the first" hasn't completed its task yet and so on.
"While a process is stopped, any additional signals that are sent to the process shall not be delivered until the process is continued, except SIGKILL (...) The default action for SIGCONT is to resume execution at the point where the process was stopped, after first handling any pending unblocked signals." (Unix standard, section Signal Concepts.)
Ordinarily, nothing special happens. When a signal X is caught while in a signal handler for Y, execution is simply transferred to the handler for X, after which the handler for Y resumes execution.
The following program demonstrates this behavior. raise(sig) sends a signal to the calling process (it's like kill(getpid(), sig)).
void hello(int unused)
{
printf("Hello, ");
raise(SIGUSR2);
printf("!\n");
}
void world(int unused)
{
printf("world");
}
int main()
{
signal(SIGUSR1, hello);
signal(SIGUSR2, world);
raise(SIGUSR1);
return 0;
}
This is "safe" because a process will accept signals only from processes with the same user ID (or root), so you can only shoot yourself in the foot this way.
Related
I have a GUI in PyQt5, which starts a QThread that reads from a serial port. The thread does quit, when it read all the data, but I want to be able to stop it when I click on a stop button. How do I do that? Here is the basic code:
# ...
class Worker(QObject):
finished = pyqtSignal()
progress = pyqtSignal(list)
def __init__(self):
QObject.__init__(self)
self._Reader = Reader()
self._Reader.progress = self.progress
self._Reader.finished = self.finished
def run(self):
self._Reader.read()
class Ui(QtWidgets.QMainWindow):
# ...
def startClicked(self):
self.thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.workerFinished)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.progress.connect(self.reportProgress)
self.thread.start()
def stopClicked(self):
# How do I stop the thread?
pass
when managing threads you can do, as states in the doc here: https://doc.qt.io/qt-5/qthread.html
You can stop the thread by calling exit() or quit().
https://doc.qt.io/qt-5/qthread.html#exit
exit:
Tells the thread's event loop to exit with a return code.
After calling this function, the thread leaves the event loop and returns from the call to QEventLoop::exec(). The QEventLoop::exec() function returns returnCode.
By convention, a returnCode of 0 means success, any non-zero value indicates an error.
https://doc.qt.io/qt-5/qthread.html#quit
quit:
Tells the thread's event loop to exit with return code 0 (success). Equivalent to calling QThread::exit(0).
This function does nothing if the thread does not have an event loop.
I assume that you read data in some data processing loop. If this assumption is wrong, then the following is not valid, of course.
You cannot call secondary thread's quit() directly from the main thread and expect that the secondary thread will process it immediately and quit the thread. The reason is that the thread is busy reading the data in the data processing loop. So you need to break the data processing loop in the secondary thread to make the event loop idle.
(Btw. do not confuse the data processing loop with the event loop. Data processing loop is the one which you have written yourself to read data from the port. The event loop is the loop created by Qt automatically after you called QThread::start() and which is processing events, signals and slots in the secondary thread. This event loop is blocked while your data processing loop is running.)
In order to break the data processing loop, you need to do two things:
call QThread::requestInterruption() from the main thread as response to some "Abort" button having been pressed (do not worry about thread safety, requesting interruption is thread safe/atomic)
within the loop in the secondary thread you need to periodically check QThread::isInterruptionRequested(), and if this returns true, then break the loop and emit worker's finished() signal
Once you broke from the data processing loop in the secondary thread, the event loop in the secondary thread becomes available for processing signals sent from the main thread.
I can see in your code that worker's finished() signal is connected to QThread::quit(). So emitting finished() from the secondary thread (after you broke from the data processing loop) will call thread's quit() which will be processed by the secondary thread's event loop (which is now idle) and it will quit the event loop and subsequently the thread and if you have connected everything correctly it will delete the worker and the thread. (though I have not checked this part of your code)
I couldn't understand how qt handle events (e.g timer event, socket event etc.) and signals in same event loop.As I understand,timer and socket events are handled via select system call(in Unix like OS).
How an event loop handle signals while sleeping because of select system call.
In Qt, signals are used to call slots. When you emit a signal, there are, roughly speaking, only 2 options for calling the corresponding slot:
Direct slot call. This can be thought of as replacing a line with a signal emitting by a line with just a slot call. An event loop is not used to process this signal itself.
Delayed slot call. In this case, the signal will be converted to an event, and the event will be posted to the receiver event loop (the event enqueues in the event loop of the thread the receiver object is living in). From now on, for the processing receiver event loop, it makes no difference whether it was a signal or an event. The event will be picked up by the event loop and will cause the slot invocation sometime later.
From Qt doc: https://doc.qt.io/qt-5/signalsandslots.html#signals
When a signal is emitted, the slots connected to it are usually
executed immediately, just like a normal function call. When this
happens, the signals and slots mechanism is totally independent of any
GUI event loop. Execution of the code following the emit statement
will occur once all slots have returned. The situation is slightly
different when using queued connections; in such a case, the code
following the emit keyword will continue immediately, and the slots
will be executed later.
As for understanding an event loop, an event loop is just a loop which process one event from an event queue on each iteration.
In short, this can be represented as follows:
QQueue<QEvent> eventQueue; // Events (and pending slot calls as well) are added to this queue
...
// How an event loop works (schematically):
while(event = eventQueue.dequeue())
{
do_what_the_event_wants_or_ignore_it(event);
}
Read also https://wiki.qt.io/Threads_Events_QObjects
To simplify the question, let's say that i have a QTimer, which will trigger its timeout event every 3000ms.
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&](){
// do sth(rely on a public data structure)
});
timer.start(3000);
The operation inside the lambda connected to the timeout event is relied on a public data structure.
And the application hold an QUdpSocket, and connect the readyRead signal with a slot function.
QUdpSocket socket;
socket.bind(45454, QUdpSocket::ReuseAddressHint);
QObject::connect(&socket, &QUdpSocket::readyRead, [&](){
//manipulate the public data structure
}
As you can see, the lambda connected to the readyRead signal manipulate the public data structure that the first lambda rely on.
So my question is, i want the function that connectted to the readyRead signal has the highest "priority", that is, even in the Qt's event loop are dealing with the timeout slot now, it can be interrupted and start the readyRead slot immediately, then after it finish, resume the timeout slot function. Is there any way to do so?
(My homework is to simulate the IEEE802.11 exposed/hidden node problem, it requires that i have to constantly listen the channel before/during sending a packet.)
(Is explicitly call QCoreApplication::processEvent will help?)
I am not familiar with the IEEE802.11 exposed/hidden node problem, however i don't think you can "interrupt" your code as you're describing.
One possible way to handle with this would be running the code for the readyRead and the timeout slots on different threads and then use some kind of synchronisation mechanism (QMutex comes to mind) to access the public data (and get its state).
i.e.
add some kind of uniqueid to identify the public_data current status
timeout_slot will acquire a lock, read the public data in a local copy and release the lock, then continue to manipulate local structure and finally before release would acquire lock again and check that the uniqueid has not been changed, if so commit your work, otherwise you'd have to start over.
readyRead_slot would acquire the lock, update the uniqueid and then continue working
I have created a simple threaded network server. The main.cpp calls app.exec() to idle, and the thread fires off as expected once I establish a connection.
In the thread's run() function, I hookup a signal from readyRead to a slot called readCommand:
connect(tcpSocketPtr, SIGNAL(readyRead()), this, SLOT(readCommand()) );
and I have defined the readCommand in the .h file for the class, as a "private slot" - since it is only called from within the class. Hope that's right.
after the connect above, the run() function returns. There is no app.exec() call or anything. Could that be the problem? Do I have to call some function to cause the thread to listen for signals?
When I send text to the port the readCommand function never fires...and I have no idea how to debug this..suggestions?
and I have defined the readCommand in the .h file for the class, as a
"private slot" - since it is only called from within the class. Hope
that's right.
Yes, that looks correct.
However, you should use int QThread::exec() [protected] inside the void QThread::run() [virtual protected] method to start the thread execution as opposed to returning almost instantly.
I see some example of SIGCHLD handler like:
void child()
{
wait(0);
signal(SIGCHLD, child);
}
void server_main()
{
...
signal(SIGCHLD, child);
...
for(;;;) {
...
switch(fork()) {
...
}
}
There two parts in the handler that confuse me:
1). SIGCHLD is caught when the child terminates or is stopped. Then why need to call wait inside the handler? The signal already arrives.
2). Why need to reinstall the SIGCHLD handler. Isn't the signal call will install the handler once and for all?
Thanks!
SIGCHLD will be triggered when the child process finished
execution. It will however still be in the process table (as a
so-called zombie process) in order to let the parent fetch the exit
value of the child. Calling wait() will clear the process table
from that child process.
If you only create n child processes then there's no reason for the signal handler still being in place when all n child processes died.
I suggest you take a look at sigaction instead, as the behaviour of signal varies between Unixes.
Isn't the signal call will install the handler once and for all?
You cannot rely on this behavior; perhaps the signal handler will be cleared, perhaps it will persist. This is part of the problem with historical signal handling. The signal(3) manpage on my system reports:
When a signal occurs, and func points to a function, it is
implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some
implementation-defined set of signals (at least including
sig) from occurring until the current signal handling has
completed.
Unreliable signals have been nearly replaced by sigaction(2)-based signals introduced in SysVr4 and standardized in POSIX.1-2001:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
These are sadly more complicated to write, but once you've written the code, you won't have to wonder if you need to re-install your handler -- and you won't have to worry that the signal will arrive a second time while handling the signal.