2011-10-19 19 views
7

Tôi đang phát triển một công cụ kiểm tra để tạo dạng sóng từ cổng song song PC. Công cụ này được thiết kế để tạo ra bất kỳ dạng sóng nào với độ chính xác thời gian của ms, vì vậy tôi sử dụng kịch bản lệnh Lua để xác định dạng sóng, GUI bắt đầu QThread mới để chạy tập lệnh khi người dùng nhấp vào nút [Bắt đầu].nanosleep() gọi từ Lua script đã tạm dừng luồng QT GUI

Ba chức năng sau cho Lua được thực hiện như các chức năng toàn cầu C++:

  • pwrite: ghi dữ liệu vào cổng song song.
  • msleep: đợi một số ms nhất định (được thực hiện bằng nanosleep())
  • in: ghi đè hàm in mặc định Lua, chức năng này sẽ thêm thông điệp vào một tiện ích QTextEdit.

khi pwrite được gọi, dữ liệu ghi được lưu trữ trong biến toàn cầu, sau đó GUI được cập nhật với khoảng 20ms để cập nhật dữ liệu cổng song song trên GUI. (20ms khoảng thời gian làm mới này không phải là một thiết kế tốt, nhưng tôi đã không tìm ra cách sử dụng tín hiệu để thực hiện cập nhật GUI khi dữ liệu thay đổi).

Công cụ này về cơ bản hoạt động ngay bây giờ. Đầu ra dạng sóng không có vấn đề gì, nhưng việc cập nhật dữ liệu cổng song song có một số vấn đề:

Khi Lua gọi msleep, GUI chỉ dừng lại, dữ liệu cổng song song chỉ cập nhật sau khi kết thúc msleep.

Vì vậy, câu hỏi của tôi là:

  1. Làm thế nào để thực hiện các phương pháp ngủ để nó sẽ không dừng lại thread GUI từ cập nhật?

  2. Cách triển khai pwrite, sao cho GUI có thể nhận tín hiệu để cập nhật dữ liệu cổng song song khi dữ liệu ghi thay đổi?

Chương trình GUI như liên kết dưới đây: Program GUI

Mã liên quan:

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

Trả lời

0

Có lẽ bạn nên sử dụng QT của msleep kể từ khi nó được cung cấp để sử dụng bởi QThread

4

Bạn chạy đúng kịch bản lệnh Lua của bạn trong chuỗi chuyên dụng. Đó là cách đúng đắn để làm điều đó - gần như. Bạn đang khởi động lại luồng mỗi lần bạn muốn chạy tập lệnh. Sai rồi. Bạn cũng đang truy cập dữ liệu trong luồng GUI từ luồng LUA mà không có bất kỳ kiểu đồng bộ nào. Điều đó không tốt. Qt cung cấp một cơ chế tuyệt vời cho điều đó dưới dạng các kết nối được xếp hàng đợi giữa các tín hiệu và các khe. Khi các cuộc gọi khe tín hiệu vượt qua các ranh giới của các chuỗi, các tham số được gói trong một QEvent và được phân phối không đồng bộ đến đích QObject. Trong mỗi chủ đề, việc cung cấp sự kiện là serialized và do đó bạn không cần phải lo lắng về tham nhũng dữ liệu, vv

Sau đây là cách nó nên được thực hiện:

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

tôi rời khỏi thi hành UI với trí tưởng tượng của bạn. Lưu ý rằng đó là mã chưa được kiểm tra. Nó có thể làm nổ tung máy tính của bạn cho tất cả những gì tôi biết.