2011-10-19 2 views
7

PC 병렬 포트에서 파형을 생성하는 테스트 도구를 개발 중입니다. 이 도구는 ms의 타이밍 정확도로 파형의 패턴을 생성하도록 설계되었으므로 루아 스크립트를 사용하여 파형 패턴을 정의하고 사용자가 [시작] 버튼을 클릭 할 때 GUI를 시작하여 새 QThread가 스크립트를 실행합니다. 루아위한Lua 스크립트에서 nanosleep() 호출이 QT GUI 스레드를 일시 중지했습니다.

다음 세 기능들은 C++ 전역 함수로서 구현된다

  • PWRITE는 병렬 포트에 데이터를 기록.
  • msleep : nanosleep()을 사용하여 구현 됨)
  • 인쇄 : Lua 기본 인쇄 기능을 덮어 쓰면 하나의 QTextEdit 위젯에 메시지가 추가됩니다.

pwrite가 호출되면 기록 된 데이터가 전역 변수에 저장되고 GUI는 20ms 간격으로 업데이트되어 GUI의 병렬 포트 데이터를 업데이트합니다. (이 20ms 간격 새로 고침 좋은 디자인이 아니지만 데이터를 변경하면 GUI 업데이트를 만드는 신호를 사용하는 방법을 알아 내지 않았습니다).

이제 도구가 기본적으로 작동합니다. 파형 출력에는 문제가 없지만 병렬 포트 데이터 업데이트에는 약간의 문제가 있습니다.

루아 호출 msleep에서 GUI 스레드가 중지되면 병렬 포트 데이터는 msleep이 끝난 후에 만 ​​업데이트됩니다.

그래서 내 질문은 :이 업데이트에서 GUI 스레드를 중지하지 않도록

  1. 어떻게 수면 방법을 구현하기 위해?

  2. 필자 데이터를 바꿀 때 GUI가 병렬 포트 데이터를 업데이트하는 신호를받을 수 있도록 pwrite를 구현하는 방법은 무엇입니까? 아래의 링크로

프로그램 GUI : Program 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, 0, 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, 0, 0, 0)) 
    { 
     err = QString(lua_tostring(L, -1)); 
     return -1; 
    } 

    lua_close(L); 

    return 0; 
} 

답변

0

이 아마도 당신이 사용해야 QT의 msleepQThread

4

귀하가 사용하기 위해 제공되기 때문에 올바르게 쓰레드에서 루아 스크립트를 실행하십시오. 그것이 올바른 방법입니다 - 거의. 스크립트를 실행할 때마다 스레드를 다시 시작합니다. 그건 틀렸어요. 또한 어떤 종류의 동기화없이 LUA 스레드에서 GUI 스레드의 데이터에 액세스하고 있습니다. 그 좋지 않다. Qt는 신호와 슬롯 간의 대기열 연결 형태로 탁월한 메커니즘을 제공합니다. 신호 슬롯 호출이 스레드 경계를 통과하면 매개 변수는 QEvent에 랩핑되고 비동기 적으로 대상 QObject에 전달됩니다. 각 스레드 내에서 이벤트 전달은 직렬화 따라서 당신은 데이터 손상 등에 대해 걱정할 필요가 없습니다

다음

이 수행해야하는 방법은 다음과 같습니다

// LUAObject.h 
#include <QObject> 

class LUAObject : public QObject 
{ 
    Q_OBJECT 
public: 
    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 etc 

LUAObject::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, -1); 
    if (data != -1) { 
     // access the parallel port HERE, NOT in the GUI thread! 
     emit hasParallelData(luaL_optint(l, 1, 0)); 
    } 
    return 0; 
} 

// returns a bool - true means we are stopped and should exit 
int L_MSleep(lua_State* l) 
{ 
    int ms = luaL_optint(l, 1, -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, -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, 1, 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, 0, 0)) 
    { 
     emit hasError(lua_tostring(L, -1)); 
     return; 
    } 

    lua_register(L, "ssleep", L_SSleep); 
    lua_register(L, "msleep", L_MSleep); 
    lua_register(L, "pwrite", L_PWrite); 
    lua_register(L, "print", 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, 0, 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의 구현을 떠나 당신의 상상력에. 그것은 테스트되지 않은 코드입니다. 내가 아는 모든 것 때문에 컴퓨터가 날아갈 수 있습니다.

관련 문제