tags:

views:

452

answers:

3

I have the following action which is executed when a certain button is pressed in a Qt application:

#include <shape.h>

void computeOperations()
{
    polynomial_t p1("x^2-x*y+1"),p2("x^2+2*y-1");
    BoundingBox bx(-4.01, 4.01,-6.01,6.01,-6.01,6.01);
    Topology3d g(bx);
    AlgebraicCurve* cv= new AlgebraicCurve(p1,p2);
    g.push_back(cv);
    g.run();
    //Other operations on g.
}

Topology3d(...), AlgebraicCurve(..), BoundingBox(...), polynomial_t(...) are user defined types defined in the corresponding header file .

Now for some values of p1 and p2, the method g.run() works perfectly.

Thus for some other values of p1 and p2, g.run() it is not working anymore as the method gets blocked somehow and the message "Application Not Responding" appears and I have to kill the Application.

I would want to have the following behavior: whenever g.run() is taking too long, gets blocked for some particular values of p1, p2, I would want to display an warning box using QMessageBox::Warning.

I try to do this with try{...} and catch{...}:

#include <shape.h>

class topologyException : public std::runtime_error
{
    public:
        topologyException::topologyException(): std::runtime_error( "topology fails" ) {}
};

void computeOperations()
{
    try
    {
        polynomial_t p1("x^2-x*y+1"),p2("x^2+2*y-1");
        BoundingBox bx(-4.01, 4.01,-6.01,6.01,-6.01,6.01);
        Topology3d g(bx);
        AlgebraicCurve* cv= new AlgebraicCurve(p1,p2);
        g.push_back(cv);
        g.run();
        //other operations on g
        throw topologyException();
    }
    catch(topologyException& topException)
    {
        QMessageBox errorBox;
        errorBox.setIcon(QMessageBox::Warning);
        errorBox.setText("The parameters are incorrect.");
        errorBox.setInformativeText("Please insert another polynomial.");
        errorBox.exec();
    }
}

This code compiles, but when it runs it does not really implement the required behavior.

For the polynomials for which g.run() gets blocked the error message box code is never reached, plus for the polynomials for which g.run() is working well, the error message box code still is reached somehow and the box appears in the application.

I am new to handling exceptions, so any help is more than welcomed.

I think the program gets blocked somewhere inside g.run() so it does not reach the exception, still I do not understand what really happens.

Still I would want to throw this exception without going into the code of g.run(), this function is implemented as part of a bigger library, which I just use in my code.

Can I have this behavior in my program without putting any try{...} catch{...} block statement in the g.run() function?

+1  A: 

You cannot achieve what you want with the use of try-catch. if g.run() takes too much time or goes into an infinite loop, that doesn't mean an exception will be thrown.

What you can do is, you can move the operations that take a lot of time into another thread. Start that thread in your event handler and wait for it to finish in your main thread for a fixed amount of time. If it does not finish, kill that thread & show your messagebox.

For further reference, read QThread, Qt Thread Support

erelender
A: 

Thanks for the suggestions. So I see how I should create the thread, something like:

class myopThread : public QThread
{
public:
 void run();
};

Then I am rewriting the run() function and put all the operations that take a lot of time in it:

void myopThread::run()
{
    polynomial_t p1("x^2-x*y+1"),p2("x^2+2*y-1");
    BoundingBox bx(-4.01, 4.01,-6.01,6.01,-6.01,6.01);
    Topology3d g(bx);
    AlgebraicCurve* cv= new AlgebraicCurve(p1,p2);
    g.push_back(cv);
    g.run();
    //other operations on g

    exec();
}

Okay everything is clear so far, still I do not see how to "Start that thread in your event handler and wait for it to finish in your main thread for a fixed amount of time. If it does not finish, kill that thread & show your messagebox."

I mean start the thread in the event handler refers somehow at using the connect (..Signal, Slot..) still I do not see how exactly this is done. I have never used QThread before so it is more then new.

Thank you very much for your help, madalina

madalina
A: 

The most elegant way to solve this that I know of is with a future value. If you haven't run across these before they can be quite handy in situations like this. Say you have a value that you'll need later on, but you can begin calculating concurrently. The code might look something like this:

SomeValue getValue() {
    ... calculate the value ...
}

void foo() {
    Future<SomeValue> future_value(getValue);
    ... other code that takes a long time ...

    SomeValue v = future_value.get();
}

Upon calling the .get() method of course, the value computed is returned, either by calling the function then and there or by retrieving the cache value calculated in another thread started when the Future<T> was created. One nice thing is that, at least for a few libraries, you can pass in a timeout parameter into the .get() method. This way if your value is taking too long to compute you can always unblock. Such elegant isn't usually achieved.

For a real life library, you might try looking into the library documented here. As I recall it wasn't accepted as the official boost futures library, but it certainly had promise. Good luck!