Russian Qt Forum

Qt => Общие вопросы => Тема начата: silart от Май 26, 2008, 07:14



Название: Потоки, слоты и сигналы
Отправлено: silart от Май 26, 2008, 07:14
Добрый день. Нужно сделать так, чтоб в GUI приложении существовал дополнительный поток, который периодически бы опрашивал устройство, и полученные данные данные передавались бы в главный поток, который обрабатывает GUI.
Вот как я пробовал решить проблему:

Код:
class DeviceScanner : public QThread
{
Q_OBJECT

private:
const QVector<boost::shared_ptr<eNod3> >& Devices;
int Interval;

private slots:
void slotTimeOut();
signals:
void Weighted(QString);

private:
void run();

public:
DeviceScanner(QObject *parent, const QVector<boost::shared_ptr<eNod3> >& devices, int interval);
~DeviceScanner();
};

DeviceScanner::DeviceScanner(QObject *parent, const QVector<boost::shared_ptr<eNod3> >& devices, int interval)
: QThread(parent), Devices(devices), Interval(interval)
{
start();
}

DeviceScanner::~DeviceScanner()
{
quit();
}

void DeviceScanner::slotTimeOut()
{
QString s;

// Че-то там...
emit Weighted( s );
}

void DeviceScanner::run()
{
QTimer t;
connect(&t, SIGNAL(timeout()), SLOT(slotTimeOut()));
t.start(Interval);

exec();
}


Проблема в том, что слот slotTimeOut() выполняет совсем не наш поток, а поток GUI. Как сделать так, чтобы сигналы таймера обрабатывались в нашем стороннем потоке?


Название: Re: Потоки, слоты и сигналы
Отправлено: Alex03 от Май 26, 2008, 11:38
Ибо получатель сигнала - потомок QThread, создан в GUI-потоке...
Способ коннекта по дефолту Qt::AutoConnection.
Цитировать
Qt::AutoConnection If the signal is emitted from the thread in which the receiving object lives, the slot is invoked directly, as with Qt::DirectConnection; otherwise the signal is queued, as with Qt::QueuedConnection.
Попробуйте так:
Код:
connect(&t, SIGNAL(timeout()), SLOT(slotTimeOut()), Qt::DirectConnection);


Название: Re: Потоки, слоты и сигналы
Отправлено: Alex03 от Май 26, 2008, 11:51
Но сразу предупрежу что сигнал Weighted(QString) по умолчанию коннектится по всей видимости между объектами главного (GUI) потока, и соответственно используется Qt::DirectConnection. Поэтому могут возникнуть некоторые грабельки уже сдесь.
Т.е. для того коннеккта нужен ConnectionType - Qt::QueuedConnection.
Возможно лучше написать свой класс, который порождать в run() и уже к нему (или прямо в нём) коннектить QTimer.



Название: Re: Потоки, слоты и сигналы
Отправлено: pastor от Май 26, 2008, 12:57
2 silart: Сделайте цикл со sleep в методе run вместо таймера и выолняйте все необходимые действия здесь (в run)


Название: Re: Потоки, слоты и сигналы
Отправлено: Alex03 от Май 26, 2008, 13:43
А то и вообще не использовать QTimer/sleep(), а пользовать чтонибудь типа select() или WaitForXXXXX() в зависимости от того что за устройство (драйвер) и какая ОС (и там и там можно задавать таймауты).


Название: Re: Потоки, слоты и сигналы
Отправлено: Sergeich от Май 26, 2008, 18:05
Как-то так:
Код:
class DeviceScanner : public QObject
{
Q_OBJECT
public:
DeviceScanner( QObject *parent, const QVector<boost::shared_ptr<eNod3> >& devices ) : QObject(parent), devs(devices) {}
public slots:
void scan();
signals:
void weighted( const QString& );
private:
const QVector<boost::shared_ptr<eNod3> >& devs;
};


class DeviceThread : public QThread
{
Q_OBJECT
public:
DeviceThread(QObject *parent, const QVector<boost::shared_ptr<eNod3> >& devices, int interval);
~DeviceScanner();
signals:
void Weighted( const QString& );
private:
const QVector<boost::shared_ptr<eNod3> >& Devices;
int Interval;
void run();
};


DeviceThread::DeviceThread(QObject *parent, const QVector<boost::shared_ptr<eNod3> >& devices, int interval)
: QThread(parent), Devices(devices), Interval(interval)
{
start();
}

DeviceThread::~DeviceThread()
{
quit();
}


void DeviceThread::run()
{
QTimer timer;
DeviceScanner scanner(0, Devices);

connect(&timer, SIGNAL(timeout()), &scanner, SLOT(scan()));
connect(&scanner, SIGNAL(weighted()), this, SIGNAL(Weighted()));
timer.start(Interval);
exec();
}