【问题标题】:Calling a function in child thread in Qt?在 Qt 的子线程中调用函数?
【发布时间】:2009-09-11 09:22:16
【问题描述】:

我有一个在不同时间调用子线程函数的主线程,但我不确定在 Qt 中这是否是正确的方法。下面的代码有什么问题并寻找更好的替代方法

当主线程释放锁子时,主线程会无限运行。

#include <QtCore/QCoreApplication>
#include <QSemaphore>
#include <QThread> 
QSemaphore sem(0);
class Background : public QThread 
{
protected:
void run() 
{ 
for(;;)
{ 
   sem.acquire(1); 
   qDebug("Child function ran");
} 
} 
};

int main(int argc, char *argv[])  
{   
QCoreApplication a(argc, argv);   
Background child; 
child.start();
qDebug("Main running"); 
qDebug("release a lock");
sem.release(1);
qDebug("Do somework in main");   
//call child
sem.release(1);
sem.release(1);
return a.exec();  
}

【问题讨论】:

    标签: c++ qt semaphore qthread


    【解决方案1】:

    编辑:修改整个帖子以涵盖基础知识。

    Background.h:

    #ifndef BACKGROUND_H
    #define BACKGROUND_H
    
    #include <QThread>
    #include <QObject>
    
    class Background : public QThread 
    {
    Q_OBJECT
    public:
       Background(QObject* parent = 0):QThread(parent){}
    protected:
       void run()
       {
          qDebug(qPrintable(QString("Child function ran in thread: %1").arg(QThread::currentThreadId())));
       }
    };
    
    class BackgroundConcurrent : public QObject
    {
    Q_OBJECT
    public:
       BackgroundConcurrent(QObject* parent = 0):QObject(parent){}
    public slots:
       void doWork() const
       {
          qDebug(qPrintable(QString("Concurrent child function ran in thread: %1").arg(QThread::currentThreadId())));
       }
    };
    
    class BackgroundTrigger : public QObject
    {
    Q_OBJECT
    public:
       BackgroundTrigger(QObject* parent = 0):QObject(parent){}
       ~BackgroundTrigger()
       {
          foreach(QObject* child, children())
          {
             QThread* childThread = qobject_cast<QThread*>(child);
             if (childThread)
                childThread->wait();
          }
       }
    public slots:
       void triggerWorker()
       {
          Background* child = new Background(this);
          child->start();
       }
    };
    
    #endif // BACKGROUND_H
    

    main.cpp:

    #include "Background.h"
    
    #include <QCoreApplication>
    #include <QtConcurrentRun>
    
    int main(int argc, char *argv[])  
    {   
    QCoreApplication a(argc, argv);   
    
    // Using QThread
    BackgroundTrigger childTrigger;
    qDebug(qPrintable(QString("Main function ran in thread: %1").arg(QThread::currentThreadId())));
    
    // Call child
    childTrigger.triggerWorker();
    childTrigger.triggerWorker();
    
    // Using QtConcurrent
    BackgroundConcurrent cchild;
    QFuture<void> future1 = QtConcurrent::run(&cchild, &BackgroundConcurrent::doWork);
    QFuture<void> future2 = QtConcurrent::run(&cchild, &BackgroundConcurrent::doWork);
    
    return 0;
    }
    

    样本输出:

    主函数在线程中运行:1087038064
    子函数在线程中运行:1091267472
    子函数在线程中运行:1093417872
    线程中运行的并发子函数:1095519120
    线程中运行的并发子函数:1097644944

    确保您在头文件上运行 moc,qmakecmake 都支持创建您的 makefile。

    这是我用来构建代码的CMakeLists.txt 文件:

    cmake_minimum_required(VERSION 2.6)
    
    #Project name
    project(TEST)
    
    #Use Qt4
    find_package(Qt4)
    
    if(QT4_FOUND)
    set(QT_USE_QTOPENGL TRUE)
    include(${QT_USE_FILE})
    
    set(LIBS
        ${QT_LIBRARIES}
        )
    
    #Source files (*.cpp, *.o)
    set(TEST_SRCS main.cpp)
    
    #Header files (*.h[pp])
    set(TEST_HDRS Background.h)
    
    #Qt macros to handle uic, moc, etc...
    QT4_WRAP_CPP(TEST_MOC ${TEST_HDRS} OPTIONS -nw)
    
    set(TEST_ALLSRC ${TEST_SRCS} ${TEST_MOC})
    
    #Create main
    add_executable(test ${TEST_ALLSRC})
    target_link_libraries(test ${LIBS})
    
    endif(QT4_FOUND)
    

    【讨论】:

    • 想测试它,但没有链接。你确定 doWork() 是在另一个线程中启动的吗?
    • 是的,它会的。我没有测试那个代码,但这是一般的想法,如果你告诉我链接错误,我也许可以在我到达我的工作机器之前修复它。同样,如果您只想在另一个线程中运行一个函数,请查看 QtConcurrent::run()
    • 我认为 gcc 要求为多态类 Background 、 BackgroundTrigger 定义析构函数和构造函数
    • main.cpp:(.text$_ZN10BackgroundD1Ev[Background::~Background()]+0xb): 未定义引用 vtable for Background' main.cpp:(.text$_ZN17BackgroundTriggerD1Ev[BackgroundTrigger::~BackgroundTrigger()]+0xb): undefined reference to vtable for BackgroundTrigger' main.cpp:(.text$_ZN17BackgroundTrigger13triggerWorkerEv[ BackgroundTrigger::triggerWorker(),BackgroundTrigger::workSignal()' main.cpp:(.text$_ZN17BackgroundTriggerC1Ev[BackgroundTrigger::BackgroundTrigger()]+0x20): 未定义引用`vtable for BackgroundTrigger'
    • 代码在这里编译并运行良好。清理目录,“qmake-qt4 -project; qmake-qt4; make”。获得的赏金,亚当!
    【解决方案2】:

    实际上,您当前对该问题的解决方案是相当不错的 hack。

    如果您更喜欢以“更清洁”的方式执行此操作,您应该在工作线程中启动一个事件循环。然后工作线程将能够接收来自主线程的信号。您可以从主线程调用子线程中的函数(使用信号/槽机制)来触发操作。

    更多详情请看这里: http://doc.trolltech.com/4.2/threads.html#per-thread-event-loop

    (提示:关键思想是在工作线程中创建接收对象;然后它的槽将在该线程中处理;或者您可以使用 MoveToThread() 函数)

    【讨论】:

    • QT 不支持这种方式的 pthread。它会忽略第二个线程。 pthread与QThread相比有什么优势?
    • QThread 不能使用,因为这些部分已经使用 pThread 构建了
    • 由于 QThread 是在 phtread 上构建的(至少在 Unix 下),您可以将现有的 pthread 包装到 QThreads 中,仍然可以访问 pthread 函数。在谷歌搜索 qthread pthread,以前有人做过。
    • 你有一段代码吗?我是 Qt 新手,很难做到
    • 对不起,我自己还没做
    【解决方案3】:

    看来您可能想为此使用信号,以适应正常的 Qt 风格。查看this question;那里接受的答案似乎也符合您的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-17
      相关资源
      最近更新 更多