Hello,
QScriptValue::call() can block thread. Is there any way to abort QScriptValue::call()? I tried to use QScriptEngine::abortEvaluation(), but this not working. Can anyone help?
Printable View
Hello,
QScriptValue::call() can block thread. Is there any way to abort QScriptValue::call()? I tried to use QScriptEngine::abortEvaluation(), but this not working. Can anyone help?
Are you calling a javascript function or a native one?
The script engine periodically calls processEvents(), so if you want to abort a call, you would have to do that using an event or as a result of a timer signal being emitted.
Yes, I know. I do this, but not working!
In C++ I initialize:
engine is object of QScriptEngine.Code:
engine.setProcessEventsInterval(100); wait_dialog->setValue(-1); connect(wait_dialog, SIGNAL(canceled()), SLOT(wait_dialog_canceled()));
Now I run script:
When I click 'Cancel' in wait_dialog then:Code:
wait_dialog->show(); QScriptValue init_funct = engine.evaluate("init"); init_funct.call(this_object);
but 'init_funct.call(this_object);' is still running and blocking thread periodically.Code:
void sth_engine::wait_dialog_canceled() { engine.abortEvaluation(); }
I didn't say anything about clicking any buttons.Quote:
Yes, I know. I do this,
Ok, here is example with timer.
Initialization:
Code:
engine.setProcessEventsInterval(100); this_object = engine.newQObject(this); timer->setSingleShot(true); connect(timer, SIGNAL(timeout()), SLOT(timeout()));
I run script:
Code:
QScriptValue init_funct = engine.evaluate("init"); timer->start(10000); init_funct.call(this_object);
If timer timeout then:
but after 10 seconds 'init_funct.call(this_object);' is still running and blocking thread periodically.Code:
void sth::timeout() { engine.abortEvaluation(); }
Apparently you are doing something wrong. This works just fine:
Code:
#include <QScriptEngine> #include <QtCore> Q_OBJECT public: Object() { connect(&timer, SIGNAL(timeout()), this, SLOT(abort())); engine.setProcessEventsInterval(1000); } void startEval() { timer.start(1000); engine.evaluate("while(true);"); } private slots: void abort() { static int cnt = 0; bool ev = engine.isEvaluating(); qDebug() << "isEvaluating?" << ev; if(!ev) timer.stop(); ++cnt; if(cnt==5) { qDebug() << "Aborting evaluation"; engine.abortEvaluation(); } } private: QScriptEngine engine; QTimer timer; }; #include "main.moc" int main(int argc, char **argv){ Object o; o.startEval(); // return app.exec(); return 0; }
The topic is: Is there any way to abort QScriptValue::call() ? and you give me example code with QSciptEngine::evaluate(). :D
Ok, here my full example:
results: "isEvaluating? false" and 'init_funct.call(this_object);' is still running and blocking thread [strike]periodically[/strike].Code:
#include <QScriptEngine> #include <QtCore> Q_OBJECT public: Object() { connect(&timer, SIGNAL(timeout()), this, SLOT(abort())); engine.setProcessEventsInterval(1000); this_object = engine.newQObject(this); } void startEval() { engine.evaluate( "function init()" "{" " for(var i = 0; i < 9000000000; ++i)" " for(var j = 0; j < 9000000000; ++j)" " var x = 10;" "}"); QScriptValue init_funct = engine.evaluate("init"); timer.start(1000); init_funct.call(this_object); qDebug() << "end of startEval()"; } private slots: void abort() { static int cnt = 0; bool ev = engine.isEvaluating(); qDebug() << "isEvaluating?" << ev; if(!ev) timer.stop(); ++cnt; if(cnt==5) { qDebug() << "Aborting evaluation"; engine.abortEvaluation(); } } private: QScriptEngine engine; QTimer timer; QScriptValue this_object; }; #include "main.moc" int main(int argc, char **argv){ Object o; o.startEval(); // return app.exec(); return 0; }
Code:
Q_OBJECT public: Object() { connect(&timer, SIGNAL(timeout()), this, SLOT(abort())); engine.setProcessEventsInterval(1000); fun = engine.evaluate("(function() { while(true); })"); } void startEval() { timer.start(1000); qDebug() << "is callable?" << fun.isFunction(); QScriptContext *context = engine.pushContext(); QScriptValue v = context->activationObject(); v.setProperty("fun", fun); engine.evaluate("fun()"); engine.popContext(); } private slots: void abort() { bool ev = engine.isEvaluating(); qDebug() << "isEvaluating?" << ev; qDebug() << "Aborting evaluation"; engine.abortEvaluation(); } private: // ... QScriptValue fun; //... };
This calls the function and aborts it after one second. QScriptValue::call() itself doesn't seem abortable as it is executed using different JavaScriptCore method than evaluate(). If you want more flexibility you can probably make your function the activation object itself, set needed arguments and trigger the context (somehow).
Thanks, this works!
However I not fully understand what for is these 4 lines:
engine.evaluate("fun()"); is enough for me.Code:
QScriptContext *context = engine.pushContext(); QScriptValue v = context->activationObject(); v.setProperty("fun", fun); engine.popContext();
Here I register "fun" to be a local property so that when I pop the context, the property is gone. this is to avoid having to register a function I want to call in the global context (as you do). This helps keep the engine clean.
Yes, because you are calling a function that is a property of the global object. Notice the difference between your code creating the function and mine. In my code the function is anonymous.Quote:
engine.evaluate("fun()"); is enough for me.