Unix signals and QCharts cause application blocking
-
Hi, all
I want to capture unix signals in qt applications, and this article (Calling Qt Functions From Unix Signal Handlers) has solved my problem very well.
However, I recently added the charts module and found that applications often get blocked. So, I deleted the unrelated application code and tried to find the cause of the blocking, but failed.
I uploaded the simple demo code to github (JCDemoDriver), hoping to get some suggestions. Thank you for your responses.Best regards.
-
After further testing, the cause of application blocking comes from timer event, not charts module.
The longer the sleep time in the timerEvent, the more likely it is to cause application blocking.
github updated: JCDemoDrivervoid JCDemoDriver::timerEvent(QTimerEvent *event) { if (event->timerId() != mTimerId) { qDebug() << __FUNCTION__ << __LINE__; return; } #if 1 static int = 0; qDebug() << __FUNCTION__ << cnt++; #endif QThread::msleep(100); // causes the application blocking }
-
@JonB
I have updated github and added a simple driver.
JCDemoDriver
Both the application and driver have been tested on Ubuntu.
The previous version was tested on IMX6U+Linux, and is the same as the Ubuntu platform, with applications permanently frozen. -
@tovax
Your timer times out every 100ms, and in the slot you sleep for 100ms. This may not be a good combination. This implies it will be close to permanently sleeping: as soon the sleep terminates the next timer timeout will occur and go back into sleep more or less immediately. BTW, if you expect the timer timeout to only start counting again after the sleep, that's not the way it works. I suggest any sleep needs at least to be for a lesser period than the repeated time outs, e.g. no more than 50 for a timeout of 100? -
@JonB
According to your suggestion, I retested it. Without a driver, there is no problem that the sleep time is greater than the timer period. For example, a timer cycle of 100 milliseconds and a sleep period of 200 milliseconds do not cause freezing. This causes the timerEvent to be counted every 200 milliseconds. -
@tovax
I would start by seeing whether in your case theactivated()
signals are being emitted and whether thehandleSig...()
slots are getting called at all.
And with judicious placement ofqDebug()
statements you may be able to find where it is "freezing". -
@JonB
I can only make sure that the driver is working correctly at the time of the freeze, and I don't know what state the socket is in. Can you give me some guidance? The thread pool was tested yesterday, and the sub threads did not output when it was frozen. -
@JonB said in Unix signals and QCharts cause application blocking:
@tovax
Your timer times out every 100ms, and in the slot you sleep for 100ms. This may not be a good combination. This implies it will be close to permanently sleeping: as soon the sleep terminates the next timer timeout will occur and go back into sleep more or less immediately. BTW, if you expect the timer timeout to only start counting again after the sleep, that's not the way it works. I suggest any sleep needs at least to be for a lesser period than the repeated time outs, e.g. no more than 50 for a timeout of 100?In the case of driving working, it is indeed a critical value for sleep time to be equal to the timing period. When the sleep time is less than the timing period, the test is no problem. When the sleep time is greater than or equal to the timing period, it can cause the application to freeze forever.
When the driver is not working, the sleep time is independent of the timing cycle, and the application works normally.
-
@JonB said in Unix signals and QCharts cause application blocking:
@tovax
Put regularqDebug()
statements intounixSignalHandler()
&qtSignalHandler()
, and also intimerEvent()
, say between every line, and see what the last output you get was.void PanelDriver::unixSignalHandler(int) { qDebug() << __FUNCTION__ << 0; char a = 1; ::write(mSocketFd[0], &a, sizeof(a)); qDebug() << __FUNCTION__ << 1; } void PanelDriver::qtSignalHandler() { qDebug() << __FUNCTION__ << 0; mSocketNotifier->setEnabled(false); qDebug() << __FUNCTION__ << 1; char tmp; ::read(mSocketFd[1], &tmp, sizeof(tmp)); qDebug() << __FUNCTION__ << 2; // do Qt stuff static int cnt = 0; qDebug() << __FUNCTION__ << cnt++; emit panelChanged(); qDebug() << __FUNCTION__ << 3; mSocketNotifier->setEnabled(true); qDebug() << __FUNCTION__ << 4; }
debug output:
unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 timerEvent QTime("18:43:29.352") qtSignalHandler 0 qtSignalHandler 1 qtSignalHandler 2 qtSignalHandler 56 qtSignalHandler 3 qtSignalHandler 4 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 0 unixSignalHandler 0 unixSignalHandler 0 unixSignalHandler 0
From the debugging output, the possible problem is:
:: write (mSocketFd [0],&a, sizeof (a));
-
@JonB said in Unix signals and QCharts cause application blocking:
@tovax
TheQTimer
you are using is not precisely "accurate". If you rely on it being exactly 100ms that is not good.If I were you I would still want to know where/why the "freeze" occurs.
Yes, I particularly want to know why this abnormal freezing occurs.
-
@tovax
The fact that you show manyunixSignalHandler 0
in a row with no alternatingunixSignalHandler 1
in between (like it does to start out with) means that you keep re-enteringunixSignalHandler()
, writing a byte, and then not even completing thewrite()
because you don't see the1
output.I don't know why that is, and why you get so many signals in a row. It seems to me their sample code approach assumes the
write()
will complete and the Qt handler willread()
after eachwrite()
before the next one. Which for whatever reason is not happening in your case. -
@JonB said in Unix signals and QCharts cause application blocking:
@tovax
The fact that you show manyunixSignalHandler 0
in a row with no alternatingunixSignalHandler 1
in between (like it does to start out with) means that you keep re-enteringunixSignalHandler()
, writing a byte, and then not even completing thewrite()
because you don't see the1
output.I don't know why that is, and why you get so many signals in a row. It seems to me their sample code approach assumes the
write()
will complete and the Qt handler willread()
after eachwrite()
before the next one. Which for whatever reason is not happening in your case.Based on your analysis and debugging output, I added a mutex, but the result is the same. I cannot understand it.
void PanelDriver::unixSignalHandler(int) { qDebug() << __FUNCTION__ << 0; QMutexLocker locker(&mMutex); char a = 1; ::write(mSocketFd[0], &a, sizeof(a)); qDebug() << __FUNCTION__ << 1; }
debug output:
unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 timerEvent QTime("19:13:56.243") qtSignalHandler 0 qtSignalHandler 1 qtSignalHandler 2 qtSignalHandler 63 qtSignalHandler 3 qtSignalHandler 4 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 1 unixSignalHandler 0 unixSignalHandler 0 unixSignalHandler 0 unixSignalHandler 0 unixSignalHandler 0
-
@JonB said in Unix signals and QCharts cause application blocking:
@tovax
The fact that you show manyunixSignalHandler 0
in a row with no alternatingunixSignalHandler 1
in between (like it does to start out with) means that you keep re-enteringunixSignalHandler()
, writing a byte, and then not even completing thewrite()
because you don't see the1
output.I don't know why that is, and why you get so many signals in a row. It seems to me their sample code approach assumes the
write()
will complete and the Qt handler willread()
after eachwrite()
before the next one. Which for whatever reason is not happening in your case.Using the enable flag has the same result.
void PanelDriver::unixSignalHandler(int) { qDebug() << __FUNCTION__ << 0; #if 0 QMutexLocker locker(&mMutex); #else static bool enable = true; if (!enable) return; #endif enable = false; char a = 1; ::write(mSocketFd[0], &a, sizeof(a)); enable = true; qDebug() << __FUNCTION__ << 1; }
-
@JonB said in Unix signals and QCharts cause application blocking:
@tovax
The fact that you show manyunixSignalHandler 0
in a row with no alternatingunixSignalHandler 1
in between (like it does to start out with) means that you keep re-enteringunixSignalHandler()
, writing a byte, and then not even completing thewrite()
because you don't see the1
output.I don't know why that is, and why you get so many signals in a row. It seems to me their sample code approach assumes the
write()
will complete and the Qt handler willread()
after eachwrite()
before the next one. Which for whatever reason is not happening in your case.It is also a failure, and continuous output "unixSignalHandler 0" after freezing.
void PanelDriver::unixSignalHandler(int) { qDebug() << __FUNCTION__ << 0; #if 0 QMutexLocker locker(&mMutex); #else if (!enable) return; #endif enable = false; char a = 1; ::write(mSocketFd[0], &a, sizeof(a)); qDebug() << __FUNCTION__ << 1; } void PanelDriver::qtSignalHandler() { qDebug() << __FUNCTION__ << 0; mSocketNotifier->setEnabled(false); qDebug() << __FUNCTION__ << 1; char tmp; ::read(mSocketFd[1], &tmp, sizeof(tmp)); qDebug() << __FUNCTION__ << 2; // do Qt stuff static int cnt = 0; qDebug() << __FUNCTION__ << cnt++; emit panelChanged(); qDebug() << __FUNCTION__ << 3; mSocketNotifier->setEnabled(true); qDebug() << __FUNCTION__ << 4; enable = true; }