3

有人能告诉我为什么这个 qt 代码在定义 ASYNC_TIMERS 时不会调用回调(即从 pthread 调用 m_timer.start 但插槽从不运行)。显然,这与从 pthread 调用有关,因为它在未定义 ASYNC_TIMERS 时工作,但我想知道如何从 pthread 修复它。我已经尝试了很多在网上找到的东西,包括 moveToThread(),调用线程运行调用 exec(),但我在这个问题上没有运气?

干杯

多定时器.h:

#pragma once

#ifndef MULTI_TIMER_H
#define MULTI_TIMER_H

#include <QThread>
#include <QTimer>
#include <QMutex>

#include <QMap>


#include <QMetaType>
#include <cassert>


class MultiTimer : public QThread
{
    Q_OBJECT

public:
    typedef void (*multiTimerCallback)(quint32 p_id);

private:
    QTimer m_timer;
    QMutex m_mutex;
    quint32 m_id;
    multiTimerCallback m_callback;
    void KillTimer(void);

public:
    // only TimerFactory is allowed to instantiate MultiTimer
    MultiTimer(quint32 p_id, multiTimerCallback p_callback);
    ~MultiTimer();
    enum TTimerType
    {
        TT_SingleShot,      ///< Timer fires only once
        TT_Repetitive       ///< Timer keeps firing repeatedly until stopped with KillTimer()
    };
    void SetTimer(quint32 p_delayInMilliseconds, MultiTimer::TTimerType timerType);

private slots:
    void Update(void);
};

#endif

计时器.cpp:

#include <QtCore/QCoreApplication>
#include "multitimer.h"
#include <stdio.h>


//--------------------------------------------------------------------------------------------------

void MultiTimer::SetTimer(quint32 p_delayInMilliseconds, MultiTimer::TTimerType timerType)
{
    QMutexLocker locker(&m_mutex);

    m_timer.setSingleShot(TT_SingleShot == timerType ? true : false);
    m_timer.start(p_delayInMilliseconds);
    //QTimer::singleShot(p_delayInMilliseconds, this,SLOT(Update()));
}

void MultiTimer::KillTimer(void)
{
    QMutexLocker locker(&m_mutex);
    m_timer.stop();
}

void MultiTimer::Update(void)
{
    QMutexLocker locker(&m_mutex);

    if (NULL != m_callback)
        m_callback(m_id);
}

MultiTimer::MultiTimer(quint32 p_id, multiTimerCallback p_callback)
    : m_id(p_id)
    , m_callback(p_callback)
{
    bool isConnected = true;
    isConnected &= this->connect(&this->m_timer, SIGNAL(timeout()), this, SLOT(Update()), Qt::QueuedConnection);
    assert(isConnected);
    //this->start();
}

MultiTimer::~MultiTimer()
{
    KillTimer();
    wait();
}


//--------------------------------------------------------------------------------------------------
#define ASYNC_TIMERS
#define GLOBAL_TIMERS

void Callback(quint32 p_id)
{
    printf("Got timered by timer %d.\n", p_id);
}

MultiTimer *mt;
void StartTimers(void)
{
    #ifndef GLOBAL_TIMERS
    mt = new MultiTimer(1, Callback);
    #endif
    mt->SetTimer(1000, MultiTimer::TT_SingleShot);
}

#ifdef ASYNC_TIMERS
pthread_t AsyncTaskThread;
void *ProcessAsyncTasks(void */*ptr*/)
{
    StartTimers();
    return NULL;
}
#endif

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    #ifdef GLOBAL_TIMERS
    mt = new MultiTimer(1, Callback);
    #endif

    #ifdef ASYNC_TIMERS
    pthread_create(&AsyncTaskThread, NULL, &ProcessAsyncTasks, NULL);
    #else
    StartTimers();
    #endif

    return a.exec();
}
4

3 回答 3

4

我认为线程和 QObjects有答案:您不能在与创建它的位置不同的线程中使用事件驱动的对象。

在您的代码中,如果GLOBAL_TIMERS启用,您将MultiTimer在主线程中创建,但调用m_timer.start()不同的。

引用文档:

事件驱动对象只能在单个线程中使用。具体来说,这适用于定时器机制和网络模块。例如,您不能在不是对象线程的线程中启动计时器或连接套接字。

所以不要那样做。(并在使用 QThread 时使用它。)

于 2011-05-18T05:09:48.693 回答
1

您需要一个 QEventLoop 来处理新线程中的信号/插槽内容。

QTimer 需要这些才能工作。

void *ProcessAsyncTasks(void */*ptr*/)
{    
    QEventLoop loop;
    StartTimers();    
    loop.exec();
    return NULL; 
}

为什么不使用 QThread?

于 2011-05-18T05:03:44.930 回答
0

好的,任何人也试图解决这个问题,我想我想通了,如果我将 m_timer 和 multitimer 对象移回主 qt 线程并“正确”发出计时器启动信号,这一切似乎都可以工作(见下文)。

可能我仍然可以在 qthread 中进行 exec 调用以从 pthread 接管并将 multitimer 和 m_timer 移至该位置,但这种方式目前有效,我得到了“由计时器 %d 计时。\n”按时输出即使在 pthread 根据需要死亡之后。:

感谢大家的投入,如果有更好的方法来做到这一点或者我忽略了一个巨大的错误,知道会很好吗?干杯

多定时器.h:

/**
    @file multitimer.h
    @brief Partial implementation of Windows-like SetTimer()/KillTimer() for Qt.

*/
#pragma once

#ifndef MULTI_TIMER_H
#define MULTI_TIMER_H

#include <QThread>
#include <QTimer>
#include <QMutex>

#include <QMap>


#include <QMetaType>
#include <cassert>


class MultiTimer : public QThread
{
    Q_OBJECT

public:
    typedef void (*multiTimerCallback)(quint32 p_id);

private:
    QTimer m_timer;
    QMutex m_mutex;
    quint32 m_id;
    multiTimerCallback m_callback;
    void KillTimer(void);

public:
    // only TimerFactory is allowed to instantiate MultiTimer
    MultiTimer(quint32 p_id, multiTimerCallback p_callback);
    ~MultiTimer();
    enum TTimerType
    {
        TT_SingleShot,      ///< Timer fires only once
        TT_Repetitive       ///< Timer keeps firing repeatedly until stopped with KillTimer()
    };
    void SetTimer(quint32 p_delayInMilliseconds, MultiTimer::TTimerType timerType);

private slots:
    void Update(void);

signals:
    void start_sig(int);
};

#endif    

计时器.cpp:

#include <QtCore/QCoreApplication>
#include "multitimer.h"
#include <stdio.h>


//--------------------------------------------------------------------------------------------------

void MultiTimer::SetTimer(quint32 p_delayInMilliseconds, MultiTimer::TTimerType timerType)
{
    QMutexLocker locker(&m_mutex);
    m_timer.setSingleShot(TT_SingleShot == timerType ? true : false);
    connect(this, SIGNAL(start_sig(int)), &m_timer, SLOT(start(int)), Qt::QueuedConnection);
    //m_timer.start(p_delayInMilliseconds);
    emit start_sig(p_delayInMilliseconds);
    disconnect(this, SIGNAL(start_sig(int)), &m_timer, SLOT(start(int)));
}

void MultiTimer::KillTimer(void)
{
    QMutexLocker locker(&m_mutex);
    m_timer.stop();
}

void MultiTimer::Update(void)
{
    QMutexLocker locker(&m_mutex);

    if (NULL != m_callback)
        m_callback(m_id);
}

MultiTimer::MultiTimer(quint32 p_id, multiTimerCallback p_callback)
    : m_id(p_id)
    , m_callback(p_callback)
{
    bool isConnected = true;
    isConnected &= this->connect(&this->m_timer, SIGNAL(timeout()), this, SLOT(Update()), Qt::QueuedConnection);
    assert(isConnected);
    //this->start();

    moveToThread(qApp->thread());
    m_timer.moveToThread(qApp->thread());
}

MultiTimer::~MultiTimer()
{
    KillTimer();
    wait();
}


//--------------------------------------------------------------------------------------------------
#define ASYNC_TIMERS
#define xGLOBAL_TIMERS

void Callback(quint32 p_id)
{
    printf("Got timered by timer %d.\n", p_id);
}

MultiTimer *mt;
void StartTimers(void)
{
    #ifndef GLOBAL_TIMERS
    mt = new MultiTimer(1, Callback);
    #endif
    mt->SetTimer(2000, MultiTimer::TT_SingleShot);
}

#ifdef ASYNC_TIMERS
pthread_t AsyncTaskThread;
void *ProcessAsyncTasks(void */*ptr*/)
{
    StartTimers();
    return NULL;
}
#endif

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    #ifdef GLOBAL_TIMERS
    mt = new MultiTimer(1, Callback);
    #endif

    #ifdef ASYNC_TIMERS
    pthread_create(&AsyncTaskThread, NULL, &ProcessAsyncTasks, NULL);
    #else
    StartTimers();
    #endif

    return a.exec();
}
于 2011-05-23T00:39:00.453 回答