2011-10-19 13 views
7

Opracowuję narzędzie testowe do generowania przebiegu z portu równoległego PC. To narzędzie jest zaprojektowane do generowania dowolnego wzoru przebiegu z dokładnością pomiaru czasu ms, więc używam skryptu Lua do definiowania wzoru przebiegu, GUI uruchamia nowy QThread, aby uruchomić skrypt, gdy użytkownik kliknie przycisk [Start].nanosleep() wywołanie z skryptu Lua przerwanego wątku QT GUI

trzy następujące funkcje dla Lua są zaimplementowane jako funkcje globalne C++:

  • pwrite: zapisu danych do portu równoległego.
  • msleep: czekaj na określony ms (zaimplementowany przy użyciu nanosleep())
  • print: nadpisuje domyślną funkcję drukowania Lua, ta doda wiadomość do jednego widgetu QTextEdit.

Po wywołaniu pwrite zapisywane dane są przechowywane w zmiennej globalnej, następnie GUI jest aktualizowane z interwałem 20ms, aby zaktualizować dane portu równoległego w GUI. (to odświeżenie 20 ms nie jest dobrym projektem, ale nie wiem, jak użyć sygnału do aktualizacji GUI po zmianie danych).

Narzędzie jest teraz zasadniczo funkcjonalne. Wyjście fali nie stanowi problemu, ale aktualizacja danych portu równoległego napotyka pewien problem:

Kiedy Lua wywołuje msleep, wątek GUI jest zatrzymany, dane portu równoległego aktualizują się dopiero po zakończeniu funkcji msleep.

Więc moje pytania to:

  1. Jak wdrożyć metodę snu tak, że nie zatrzyma wątek GUI z aktualizacją?

  2. Jak zaimplementować pwrite, aby GUI mógł odbierać sygnał aktualizujący dane portu równoległego po zmianie danych pisanych?

GUI Program jak na poniższym linkiem: Program GUI

dany przepis:

/* 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; 
} 

Odpowiedz

0

Być może należy użyć Qt msleep ponieważ służą do użytku przez QThread

4

You poprawnie uruchom swój skrypt Lua w dedykowanym wątku. To właściwa droga - prawie. Za każdym razem, gdy chcesz uruchomić skrypt, uruchamiasz ponownie wątek. To jest źle. Uzyskujesz także dostęp do danych w wątku GUI z wątku LUA bez żadnej synchronizacji. To nie jest dobrze. Qt zapewnia doskonały mechanizm do tego w postaci oczekujących w kolejce połączeń między sygnałami i gniazdami. Gdy wywołania przedziału sygnałowego przekraczają granice wątków, parametry zostają zawinięte w QEvent i zostają asynchronicznie dostarczone do celu QObject. W obrębie każdej nici, dostawa wydarzenie jest w odcinkach, a więc nie trzeba się martwić o uszkodzenia danych itp

Oto jak należy to zrobić:

// 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; 
} 

zostawiam realizację UI do twojej wyobraźni. Zwróć uwagę, że jest to niesprawdzony kod. Może wysadzić twój komputer ze wszystkiego, co wiem.

Powiązane problemy