c – 来自Lua脚本的nanosleep()调用暂停了QT GUI线程

c – 来自Lua脚本的nanosleep()调用暂停了QT GUI线程,第1张

概述我正在开发一种测试工具,用于从PC并行端口生成波形.此工具旨在生成任何波形图案,定时精度为ms,因此我使用Lua脚本定义波形图案,当用户单击[开始]按钮时,GUI启动新的QThread以运行脚本. Lua的以下三个函数实现为C全局函数: > pwrite:将数据写入并行端口. > msleep:等待某个ms(使用nanosleep()实现) > print:覆盖Lua默认打印功能,此功能会将消息附 我正在开发一种测试工具,用于从PC并行端口生成波形.此工具旨在生成任何波形图案,定时精度为ms,因此我使用Lua脚本定义波形图案,当用户单击[开始]按钮时,GUI启动新的QThread以运行脚本.

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线程所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1241029.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存