How can I interrupt a function?
-
wrote on 6 Apr 2012, 00:58 last edited by
I have an API that I must use who's functions can hang indefinitely (due to a hardware driver). These functions cannot be called asynchronously. I have to be able to call a function and detect that I didn't get back after a certain amout of time. In that case, I must somehow cancel that function call. I tried putting the function call into a thread, making it a slot, and calling it via a queued connection. However, there is no way to interrupt it. I thought if I could get an interrupt, I could terminate the thread. I tried setting a QTimer, but a QTimer will not interrupt a function that is executing. Once the function is running there is no way to wrestle control back. Does anyone know how I can solve this problem? I can't find anyting on the internet quite like this.
-
wrote on 6 Apr 2012, 03:19 last edited by
I also tried making the call to the API function using QtConcurrent::run(). This at least gives me the ability to get my QTimer timeout signal, but it doesn't do me any good, becuase there is nothing I can do with that knowledge. I can't cancel the function that is running under QtConcurrent::run().
-
wrote on 6 Apr 2012, 09:30 last edited by
The only thing I can think of, is to indeed use a thread to run your function in, and then simply terminate the tread. Note that the terminate slot() is on QThread itself, and does not need a running eventloop in the thread. If you want to terminate on a timeout, you might even subclass QThread to add that timer (from the constructor, not from the run method!) and connect it to the terminate slot internally.
Something like this:
@
//declaration
SelfKillingThread: public QThread
{
Q_OBJECT;
public:
SelfKillingThread(int timeout, QObject* parent = 0);private:
QTimer* m_timer;
}//implementation
SelfKillingTimer::SelfKillingTimer(int timeout, QObject* parent):
QThread(parent),
m_timer(new QTimer(this))
{
m_timer->setInterval(timeout);
m_timer->setSingleShot(true);
connect(m_timer, SIGNAL(timeout()), this, SLOT(terminate()));
connect(this, SIGNAL(finished()), m_timer, SLOT(stop()));
connect(this, SIGNAL(terminated()), m_timer, SLOT(stop()));
connect(this, SIGNAL(started()), m_timer, SLOT(start()));
}@
Heed the warning on using terminate() from the Qt documentation though!
-
wrote on 7 Apr 2012, 10:09 last edited by
This indeed sounds like an example of where QThread::terminate() may be of use. I would still be worried about resource handling, since the driver cannot guarantee that it closes file handles et cetera if the thread is terminated.
Is there no way to fix the driver or get an update?
-
wrote on 9 Apr 2012, 18:40 last edited by
Unfortunately, QTimer will not trigger a timeout while the task is doing something, and therefore if a function in the task is hung, the timeout will not trigger ever. You can test this by signalling a function in the task to do something that takes 30 seconds, and setting the timeout to 10 seconds. You won't get the timeout. It doesn't matter if the QTimer is defined inside the thread, or outside the thread. I've tried both.
I've also tried simulating the case where the function is truly hung, and I had to go to task manager and shut down the processes, including QtCreator one at a time, and restart the computer - and it takes forever.
-
wrote on 9 Apr 2012, 18:43 last edited by
Yes, it will trigger, but not if you put it in the same thread.
-
wrote on 9 Apr 2012, 18:57 last edited by
I wish that were true. That's the very first thing I tried. In the main window a HardwareManagerThread is created. The main window starts a QTimer for 10 seconds, then signals a function in the HardwareManagerThread over a queued connection. The function runs for 30 seconds. After the 30 seconds is up, the 10 second timer triggers (20 seconds late). Had the function hung, the timer would have never triggered. Try it. I might have done something wrong, but the above describes what I have done, and that is the results I get.
-
wrote on 10 Apr 2012, 07:37 last edited by
Might be, but the suggestion was to run the hardware function in a separate thread from the main thread, and then use a time in the main tread connected to the terminate() slot of the QThread object that is managing the hardware-related function. There is no need to handle that signal inside the thread itself, the signal stays in the main thread.
I don't see why that would not work. Obviously, you can't listen for a (cross-thread) signal while you're in a blocking function inside the thread itself. But in the suggested setup, that is not needed.
-
wrote on 10 Apr 2012, 12:13 last edited by
[quote author="Andre" date="1334043449"]Might be, but the suggestion was to run the hardware function in a separate thread from the main thread, and then use a time in the main tread connected to the terminate() slot of the QThread object that is managing the hardware-related function. There is no need to handle that signal inside the thread itself, the signal stays in the main thread.
I don't see why that would not work. Obviously, you can't listen for a (cross-thread) signal while you're in a blocking function inside the thread itself. But in the suggested setup, that is not needed.[/quote]
This works, unless someone moves the QThread object itself to live inside the thread (what is wrong).
-
wrote on 10 Apr 2012, 12:17 last edited by
[quote author="Gerolf" date="1334060023"]This works, unless someone moves the QThread object itself to live inside the thread (what is wrong).[/quote]
Indeed. That would be Doing It Wrong (TM). -
wrote on 10 Apr 2012, 16:18 last edited by
[quote author="Andre" date="1334043449"]Might be, but the suggestion was to run the hardware function in a separate thread from the main thread, and then use a time in the main tread connected to the terminate() slot of the QThread object that is managing the hardware-related function. There is no need to handle that signal inside the thread itself, the signal stays in the main thread. I don't see why that would not work. Obviously, you can't listen for a (cross-thread) signal while you're in a blocking function inside the thread itself. But in the suggested setup, that is not needed.[/quote]
Let me re-iterate. No signal in any thread from any timer declared anywhere is signaled once the hardware function blocks and never returns. -
wrote on 10 Apr 2012, 20:13 last edited by
Then I don't know what that function is doing, but it seems to block the whole system.
-
wrote on 10 Apr 2012, 20:18 last edited by
All I'm doing is simulating a function that might hang. The following function blocks all timers in all threads in the system until it is finished. If you replace the for loop with while(true), it will block all timers in all threads forever.
@
bool HardwareManager::myFunc()
{
double a;
for (int i = 0; i < 100; i++)
{
for (unsigned j = 0; j < 10000000; j++)
{
a += j * 3.0;
}
}qDebug() << "finishing myFunc"; return true;
}
@Edit: please use code tags around code sections; Andre
1/15