Lua的以下三个函数实现为C全局函数:
> pwrite:将数据写入并行端口.
> msleep:等待某个ms(使用nanosleep()实现)
> print:覆盖Lua默认打印功能,此功能会将消息附加到一个QTextEdit小部件.
当调用pwrite时,写入的数据存储在全局变量中,然后以20ms的间隔更新GUI以更新GUI上的并行端口数据. (这20ms间隔刷新不是一个好的设计,但我还没弄清楚如何在数据改变时使用信号进行GUI更新).
该工具现在基本上是功能性的.波形输出没有问题,但并行端口数据更新有一些问题:
当Lua调用msleep时,GUI线程停止,并行端口数据仅在msleep结束后更新.
所以我的问题是:
>如何实现sleep方法,以便它不会阻止GUI线程更新?
>如何实现pwrite,以便GUI在写入数据发生变化时可以接收信号来更新并行端口数据?
程序GUI如下链接:
相关代码:
/* common.cpp file */int L_MSleep(lua_State* l){ int milisec=0; struct timespec req={0,0}; time_t sec; milisec=luaL_optint(l,1,0); // obtain parameter if (milisec==0) return 0; sec=(int)(milisec/1000); milisec=milisec-(sec*1000); req.tv_sec=sec; req.tv_nsec=milisec*1000000L; while(nanosleep(&req,&req)==-1) continue; return 1;}/* LuaRunner.cpp file */LuaRunner::LuaRunner(QObject *parent) : QThread(parent){ runlua = false;}voID LuaRunner::run(){ QString err = ""; runlua = true; LUA_RunScript(this->ff,err); runlua = false; if(err != "") { emit errorMessage(err); }}int LuaRunner::LUA_RunScript(QString ff,QString &err){ L = lua_open(); luaL_openlibs(L); if (luaL_loadfile(L,ff.toAscii()) || lua_pcall(L,0)) { err = QString(lua_tostring(L,-1)); return -1; } lua_register(L,"ssleep",L_SSleep); lua_register(L,"msleep",L_MSleep); lua_register(L,"pwrite",L_PortWrite); lua_register(L,"print",L_Log); lua_getglobal(L,"dotest"); if (!lua_isfunction(L,-1)) { err = QString("Test function(dotest) should be a function"); return -1; } if(lua_pcall(L,-1)); return -1; } lua_close(L); return 0;}解决方法 您正确地在专用线程中运行Lua脚本.这是正确的方法 – 差不多.每次要运行脚本时都要重新启动线程.那是错的.您还从LUA线程访问GUI线程中的数据,而不进行任何同步.这不好. Qt以信号和插槽之间的排队连接的形式提供了一种出色的机制.当signal-slot调用通过线程边界时,参数将被包装在QEvent中并异步传递给目标QObject.在每个线程中,事件传递是序列化的,因此您不必担心数据损坏等.
这是应该如何做的:
// LUAObject.h#include <QObject>class LUAObject : public QObject{ Q_OBJECTpublic: LUAObject(QObject * parent = 0);public slots: voID setScript(const QString &); voID runScript(); voID stop();signals: voID hasError(const QString &); voID finished(); voID hasParallelData(int); voID hasMessage(const QString &);private: QString script; bool stop;}// LUAObject.cpp// whatever Lua includes you need etcLUAObject::LUAObject(QObject* p) : QObject(p){}voID LUAObject::stop() { stopped = true; } voID LUAObject::setScript(const QString & scr){ script = scr; }int L_PWrite(lua_State* l){ int data = luaL_optint(l,-1); if (data != -1) { // access the parallel port HERE,NOT in the GUI thread! emit hasParallelData(luaL_optint(l,0)); } return 0;}// returns a bool - true means we are stopped and should exitint L_MSleep(lua_State* l){ int ms = luaL_optint(l,-1); if (ms == -1) return 0; QApplication::processEvents(QEventLoop::WaitForMoreEvents,ms); lua_pushBoolean(l,stopped); // event processing would run the stop() slot call return 1;}int L_SSleep(lua_State* l){ int secs = luaL_optint(l,-1); if (secs == -1) return 0; QApplication::processEvents(QEventLoop::WaitForMoreEvents,secs*1000); lua_pushBoolean(l,stopped); // event processing would run the stop() slot call return 1;}int L_Log(lua_State* l){ const char * msg = luaL_optstring(l,0); if (!msg) return 0; emit hasMessage(msg); return 0;}class Lua // RAII{public: explicit Lua(lua_state * l) : L(l) {} ~Lua() { lua_close(L); } operator lua_state*() const { return L; }private: lua_state * L; Q_disABLE_copY(LUA)};LUAObject::runScript(){ stopped = false; Lua L(lua_open()); luaL_openlibs(L); if (luaL_loadbuffer(L,script.toAscii().constData(),script.length(),"script") || lua_pcall(L,0)) { emit hasError(lua_tostring(L,-1)); return; } lua_register(L,L_SSleep); lua_register(L,L_MSleep); lua_register(L,L_PWrite); lua_register(L,L_Log); lua_getglobal(L,"dotest"); if (!lua_isfunction(L,-1)) { emit hasError("Test function(dotest) should be a function"); return; } if(lua_pcall(L,0)) { emit hasError(lua_tostring(L,-1)); return; } emit finished();}// main.cpp#include <QApplication>#include <QMetaMethod>#include "LUAObject.h"...int main(int argc,char** argv){ QApplication(argc,argv); MainWindow window; ... QThread thread; LUAObject lua; thread.start(QThread::TimeCriticalPriority); lua.movetoThread(&thread); ... // NOTE: you can ONLY connect to LUAObject slots,you CANNOT call them // directly since it runs in a separate thread! connect(&window,SIGNAL(startClicked()),&lua,SLOT(runScript()); connect(&lua,SIGNAL(hasError(QString)),&window,SLOT(luaError(QString))); ... window.show(); int rc = qApp->exec(); QMetaObject::invokeMethod(&lua,SLOT(stop())); // cross-thread slot invocation thread.exit(); thread.wait(); return rc;}
我将UI的实现留给您的想象力.请注意,它是未经测试的代码.它可能会让我知道的所有东西都爆炸.
总结以上是内存溢出为你收集整理的c – 来自Lua脚本的nanosleep()调用暂停了QT GUI线程全部内容,希望文章能够帮你解决c – 来自Lua脚本的nanosleep()调用暂停了QT GUI线程所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)