April 6, 2012

neveralull neveralull
Lab Rat
31 posts

How can I interrupt a function?

 

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.

14 replies

April 6, 2012

neveralull neveralull
Lab Rat
31 posts

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().

April 6, 2012

Andre Andre
Robot Herder
6393 posts

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:

  1. //declaration
  2. SelfKillingThread: public QThread
  3. {
  4. Q_OBJECT;
  5. public:
  6. SelfKillingThread(int timeout, QObject* parent = 0);
  7.  
  8. private:
  9. QTimer* m_timer;
  10. }
  11.  
  12. //implementation
  13. SelfKillingTimer::SelfKillingTimer(int timeout, QObject* parent):
  14.    QThread(parent),
  15.    m_timer(new QTimer(this))
  16. {
  17.   m_timer->setInterval(timeout);
  18.   m_timer->setSingleShot(true);
  19.   connect(m_timer, SIGNAL(timeout()), this, SLOT(terminate()));
  20.   connect(this, SIGNAL(finished()), m_timer, SLOT(stop()));
  21.   connect(this, SIGNAL(terminated()), m_timer, SLOT(stop()));
  22.   connect(this, SIGNAL(started()), m_timer, SLOT(start()));
  23. }

Heed the warning on using terminate() from the Qt documentation though!

April 7, 2012

miroslav miroslav
Lab Rat
228 posts

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?

 Signature 

Mirko Boehm | .(JavaScript must be enabled to view this email address) | KDE e.V.
FSFE Fellow
Qt Certified Specialist

April 9, 2012

neveralull neveralull
Lab Rat
31 posts

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.

April 9, 2012

Andre Andre
Robot Herder
6393 posts

Yes, it will trigger, but not if you put it in the same thread.

April 9, 2012

neveralull neveralull
Lab Rat
31 posts

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.

April 9, 2012

Volker Volker
Ant Farmer
5428 posts

@Andre: As long as the hardware function blocks, the event loop of the thread is stalled and the timeout signal event cannot be delivered. Or do I miss something?

April 10, 2012

Andre Andre
Robot Herder
6393 posts

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.

April 10, 2012

Volker Volker
Ant Farmer
5428 posts

@Andre: Ah, yes. You’re completely right. I misread the post in the sense that the timer should live in the secondary thread.

April 10, 2012

Gerolf Gerolf
Robot Herder
3252 posts

Andre wrote:
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.

This works, unless someone moves the QThread object itself to live inside the thread (what is wrong).

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

April 10, 2012

Andre Andre
Robot Herder
6393 posts

Gerolf wrote:
This works, unless someone moves the QThread object itself to live inside the thread (what is wrong).

Indeed. That would be Doing It Wrong ™.

April 10, 2012

neveralull neveralull
Lab Rat
31 posts

Andre wrote:
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.

Let me re-iterate. No signal in any thread from any timer declared anywhere is signaled once the hardware function blocks and never returns.

April 10, 2012

Andre Andre
Robot Herder
6393 posts

Then I don’t know what that function is doing, but it seems to block the whole system.

April 10, 2012

neveralull neveralull
Lab Rat
31 posts

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.

  1. bool HardwareManager::myFunc()
  2. {
  3.     double a;
  4.     for (int i = 0; i < 100; i++)
  5.     {
  6.         for (unsigned j = 0; j < 10000000; j++)
  7.         {
  8.             a += j * 3.0;
  9.         }
  10.     }
  11.  
  12.     qDebug() << "finishing myFunc";
  13.     return true;
  14. }

Edit: please use code tags around code sections; Andre

 
  ‹‹ How to ensure comparison operator is "complete"?      Progressbar problem ››

You must log in to post a reply. Not a member yet? Register here!