2011-10-19 4 views
7

PCパラレルポートから波形を生成するためのテストツールを開発しています。このツールは、タイミング精度がmsの任意の波形パターンを生成するように設計されているため、ユーザーが[Start]ボタンをクリックしたときにスクリプトを実行する新しいQThreadを開始するために、波形パターンを定義するLuaスクリプトを使用します。 LuaのためLuaスクリプトからのnanosleep()呼び出しがQT GUIスレッドを一時停止しました

次の三つの機能は、C++のグローバル関数として実装されている:

  • PWRITEは:パラレルポートにデータを書き込みます。
  • msleep:nanosleep()を使用して実装しました。
  • print:Luaのデフォルトの印刷機能を上書きします。これは1つのQTextEditウィジェットにメッセージを追加します。

pwriteが呼び出されると、書き込まれたデータがグローバル変数に格納され、GUIのパラレルポートデータを更新するために20ms間隔でGUIが更新されます。 (この20ms間隔のリフレッシュは良い設計ではありませんが、データが変更されたときに信号を使ってGUIを更新する方法を理解していません)。

このツールは基本的に機能しています。波形出力に問題はありませんが、パラレルポートデータの更新には何らかの問題があります。

Luaコールmsleepでは、GUIスレッドは停止し、パラレルポートデータはmsleep終了後にのみ更新されます。

だから私の質問は以下のとおりです。

  1. それが更新からGUIスレッドを停止しないようにスリープメソッドを実装する方法は?

  2. 書込みデータが変更されたときにGUIがパラレルポートデータを更新する信号を受け取れるように、pwriteを実装する方法は? Program 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, 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

それはあなたがQThread

4

で使用するために用意されているので、おそらくあなたはQTのmsleepを使用する必要があります専用のスレッドでLuaスクリプトを正しく実行してください。それは正しい方法です - ほとんど。スクリプトを実行するたびにスレッドを再起動します。それは間違っている。また、GUIスレッド内のデータにLUAスレッドからアクセスすることもできます。それは良いことではありません。 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の実装を残しますあなたの想像力に。テストされていないコードです。私が知っているすべてのためにあなたのコンピュータを爆破するかもしれません。

関連する問題