2011-05-18 35 views
2

谁能告诉我为什么这个Qt代码不会调用定义ASYNC_TIMERS回调时(即m_timer.start从并行线程调用,但插槽从未运行)。显然,这是从并行线程被调用时做没有定义ASYNC_TIMERS,但我想知道如何从并行线程修复它,因为它的工作原理。我尝试了许多在网上找到的东西,包括moveToThread(),调用线程运行时调用exec(),但我对这个问题没有运气?QT的信号/槽和并行线程不玩好起来

干杯

multitimer.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 

timer.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(); 
} 
+0

你在同一时间同时使用GLOBAL_TIMERS和ASYNC_TIMERS? – 0xbaadf00d 2011-05-18 06:40:43

回答

1

你需要一个QEventLoop处理信号/槽的东西,在新的线程。

QTimer需要这些工作。

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

为什么不使用QThread?

+0

我会给这个一展身手,但随着我们从并行线程的外部库事件,它是不是真的为我们最终的设计是可行的。我曾尝试使用multitimers run方法(因为它是一个线程)来调用exec,但没有奏效。 – othane 2011-05-18 23:05:14

+0

我认为你应该再次看看这些课程是做什么和需要的,你会找到更好的答案。我很难找出一些有助于理解而不知道你需要达到什么的东西。 – 0xbaadf00d 2011-05-19 05:12:38

3

我认为Threads and QObjects了答案:你不能在不同的线程比你创建它在那里使用事件驱动的对象。

在你的代码,如果启用GLOBAL_TIMERS,你会在你的主线程 创建MultiTimer,但在不同的一个叫m_timer.start()

报价文档:

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

所以不这样做。 (并使用QThread,而你在它。)

+0

我没有看到他使用活动? – 2011-05-18 06:15:30

+0

'm_timer.start(p_delayInMilliseconds);有些人来说 – Mat 2011-05-18 06:19:58

+0

当GLOBAL_TIMERS定义(如果在这种情况下,它不工作),它的工作后'会生成事件。这是因为Multitimer对象是在带有事件循环的线程中创建的。请注意,他询问为什么在定义ASYNC_TIMERS时不起作用。该版本不起作用,因为在创建MultiTimer对象的线程中没有事件循环。 – 0xbaadf00d 2011-05-18 06:24:45

0

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

可能我仍然可以在qthread中调用一个exec来调用pthread,并将multitimer和m_timer移动到那个地方,但这种方式现在可行,而且我得到了“通过定时器%d得到了时间。\ n “输出准时,即使在pthread死后视为需要。:

感谢所有的输入,如果有更好的方法来做到这一点或一个大规模的错误,我忽略了这将是很好的知道吗?干杯

multitimer.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  

timer.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(); 
} 
+0

你想达到什么目的?除非我明白你想要什么,否则我无法帮助你。如果你所需要的只是一个QTimer,它以某个间隔调用某个函数,你根本不需要创建线程。如果你想让QTimers从不同的线程运行,你需要QEventLoop在这些线程中运行。这是您的主线程中所拥有的,因为QCoreApplication提供了它。 – 0xbaadf00d 2011-05-23 05:07:16