#ifndef SPEEDOMETERTHREAD_H
#define SPEEDOMETERTHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class SpeedometerThread
: public QThread{
Q_OBJECT
public:
SpeedometerThread
(QObject *parent
= 0);
~SpeedometerThread();
void requestNewSpeedometer
(const QString &hostName, quint16 port
);
// to request a new speedometer, //and the result is delivered by the
//newSpeedometer() signal
void run();
signals:
void newSpeedometer
(const QString &speedometer
);
//The reault of invoking the requestNewSpeedometer() void error
(int socketError,
const QString &message
);
//If any error occurs, the error() signal is emitted.
private:
QString hostName;
//requestNewSpeedometer() is called from the main, GUI thread, but the host name and port quint16 port; //values it stores will be accessed from SpeedometerThread's thread.
QMutex mutex;
// Because we will be reading and writing FortuneThread's data members from different threads //concurrently, we use QMutex to synchronize access.
bool quit;
};
#endif // SPEEDOMETERTHREAD_H
#ifndef SPEEDOMETERTHREAD_H
#define SPEEDOMETERTHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class SpeedometerThread : public QThread
{
Q_OBJECT
public:
SpeedometerThread(QObject *parent = 0);
~SpeedometerThread();
void requestNewSpeedometer(const QString &hostName, quint16 port); // to request a new speedometer,
//and the result is delivered by the
//newSpeedometer() signal
void run();
signals:
void newSpeedometer(const QString &speedometer); //The reault of invoking the requestNewSpeedometer()
void error(int socketError, const QString &message); //If any error occurs, the error() signal is emitted.
private:
QString hostName; //requestNewSpeedometer() is called from the main, GUI thread, but the host name and port
quint16 port; //values it stores will be accessed from SpeedometerThread's thread.
QMutex mutex; // Because we will be reading and writing FortuneThread's data members from different threads
//concurrently, we use QMutex to synchronize access.
QWaitCondition cond;
bool quit;
};
#endif // SPEEDOMETERTHREAD_H
To copy to clipboard, switch view to plain text mode
#include <QtNetwork>
#include "speedometerthread.h"
SpeedometerThread
::SpeedometerThread(QObject *parent
){
}
SpeedometerThread::~SpeedometerThread()
{
mutex.lock();
quit = true; // sets quit to true
cond.wakeOne(); // wakes up the thread
mutex.unlock();
wait(); //waits for the thread to exit before returning. This lets the while loop in run() will finish
// its current iteration. When run() returns, the thread will terminate and be destroyed.
}
void SpeedometerThread
::requestNewSpeedometer(const QString &hostName, quint16 port
) {
QMutexLocker locker
(&mutex
);
// stores the host name and port of the fortune server as member data, and we this->hostName = hostName; // lock the mutex with QMutexLocker to protect this data. We then start the
this->port = port; //thread, unless it is already running.
if (!isRunning())
start();
else
cond.wakeOne(); // because the thread falls asleep waiting for a new request, we needed to wake it up
// again when a new request arrives. QWaitCondition is often used in threads to
// signal a wakeup call like this.
}
void SpeedometerThread::run()
{
mutex.lock(); // acquiring the mutex lock
QString serverName
= hostName;
// fetching the host name and port from the member data quint16 serverPort = port;
mutex.unlock(); // releasing the lock again
while (!quit)
{
const int Timeout = 5 * 1000; // (in ms)
QTcpSocket socket;
//creating a QTcpSocket on the stack socket.connectToHost(serverName, serverPort); // starts an asynchronous operation which, after control
// returns to Qt's event loop, will cause QTcpSocket
// to emit connected() or error().
if (!socket.waitForConnected(Timeout)) //since we are running in a non-GUI thread, we do not have to worry
{ // about blocking the user interface. So instead of entering an event loop, we simply call
// QTcpSocket::waitForConnected(). This function will wait, blocking the calling thread,
//until QTcpSocket emits connected() or an error occurs. If connected() is emitted, the function returns
// true; if the connection failed or timed out (which in this example happens after 5 seconds),
// false is returned. QTcpSocket::waitForConnected(), like the other waitFor...() functions, is part of
//QTcpSocket's blocking API.
emit error(socket.error(), socket.errorString());
return;
}
while (socket.bytesAvailable() < (int)sizeof(quint16))
{ // we have a connected socket to work with. Now it's time to see what the fortune server has sent us.
if (!socket.waitForReadyRead(Timeout)) // read the size of the packet. Although we are only reading
{ // two bytes here, and the while loop may seem to overdo it, waiting for data using
// QTcpSocket::waitForReadyRead(). For as long as we still need more data, we call waitForReadyRead().
// If it returns false, we abort the operation. After this statement, we know that we
//have received enough data.
emit error(socket.error(), socket.errorString());
return;
}
}
quint16 blockSize;
QDataStream in
(&socket
);
// create a QDataStream object, passing the socket to QDataStream's constructor, in.
setVersion(QDataStream::Qt_4_0);
// and set the stream protocol version to QDataStream::Qt_4_0, and read in >> blockSize; // the size of the packet.
while (socket.bytesAvailable() < blockSize)
{ //a loop that waits for more data by calling QTcpSocket::waitForReadyRead(). In this loop, we're waiting
// until QTcpSocket::bytesAvailable() returns the full packet size.
if (!socket.waitForReadyRead(Timeout))
{
emit error(socket.error(), socket.errorString());
return;
}
}
mutex.lock();
in >> speedometer; //use QDataStream to read the fortune string from the packet. The resulting
emit newSpeedometer(speedometer); // speedometer is delivered by emitting newSpeedometer().
cond.wait(&mutex); // acquire the mutex so that we can safely read from our member data.
serverName = hostName; // We then let the thread go to sleep by calling QWaitCondition::wait().
serverPort = port;
mutex.unlock();
}
}
#include <QtNetwork>
#include "speedometerthread.h"
SpeedometerThread::SpeedometerThread(QObject *parent)
: QThread(parent), quit(false)
{
}
SpeedometerThread::~SpeedometerThread()
{
mutex.lock();
quit = true; // sets quit to true
cond.wakeOne(); // wakes up the thread
mutex.unlock();
wait(); //waits for the thread to exit before returning. This lets the while loop in run() will finish
// its current iteration. When run() returns, the thread will terminate and be destroyed.
}
void SpeedometerThread::requestNewSpeedometer(const QString &hostName, quint16 port)
{
QMutexLocker locker(&mutex); // stores the host name and port of the fortune server as member data, and we
this->hostName = hostName; // lock the mutex with QMutexLocker to protect this data. We then start the
this->port = port; //thread, unless it is already running.
if (!isRunning())
start();
else
cond.wakeOne(); // because the thread falls asleep waiting for a new request, we needed to wake it up
// again when a new request arrives. QWaitCondition is often used in threads to
// signal a wakeup call like this.
}
void SpeedometerThread::run()
{
mutex.lock(); // acquiring the mutex lock
QString serverName = hostName; // fetching the host name and port from the member data
quint16 serverPort = port;
mutex.unlock(); // releasing the lock again
while (!quit)
{
const int Timeout = 5 * 1000; // (in ms)
QTcpSocket socket; //creating a QTcpSocket on the stack
socket.connectToHost(serverName, serverPort); // starts an asynchronous operation which, after control
// returns to Qt's event loop, will cause QTcpSocket
// to emit connected() or error().
if (!socket.waitForConnected(Timeout)) //since we are running in a non-GUI thread, we do not have to worry
{ // about blocking the user interface. So instead of entering an event loop, we simply call
// QTcpSocket::waitForConnected(). This function will wait, blocking the calling thread,
//until QTcpSocket emits connected() or an error occurs. If connected() is emitted, the function returns
// true; if the connection failed or timed out (which in this example happens after 5 seconds),
// false is returned. QTcpSocket::waitForConnected(), like the other waitFor...() functions, is part of
//QTcpSocket's blocking API.
emit error(socket.error(), socket.errorString());
return;
}
while (socket.bytesAvailable() < (int)sizeof(quint16))
{ // we have a connected socket to work with. Now it's time to see what the fortune server has sent us.
if (!socket.waitForReadyRead(Timeout)) // read the size of the packet. Although we are only reading
{ // two bytes here, and the while loop may seem to overdo it, waiting for data using
// QTcpSocket::waitForReadyRead(). For as long as we still need more data, we call waitForReadyRead().
// If it returns false, we abort the operation. After this statement, we know that we
//have received enough data.
emit error(socket.error(), socket.errorString());
return;
}
}
quint16 blockSize;
QDataStream in(&socket); // create a QDataStream object, passing the socket to QDataStream's constructor,
in.setVersion(QDataStream::Qt_4_0); // and set the stream protocol version to QDataStream::Qt_4_0, and read
in >> blockSize; // the size of the packet.
while (socket.bytesAvailable() < blockSize)
{ //a loop that waits for more data by calling QTcpSocket::waitForReadyRead(). In this loop, we're waiting
// until QTcpSocket::bytesAvailable() returns the full packet size.
if (!socket.waitForReadyRead(Timeout))
{
emit error(socket.error(), socket.errorString());
return;
}
}
mutex.lock();
QString speedometer;
in >> speedometer; //use QDataStream to read the fortune string from the packet. The resulting
emit newSpeedometer(speedometer); // speedometer is delivered by emitting newSpeedometer().
cond.wait(&mutex); // acquire the mutex so that we can safely read from our member data.
serverName = hostName; // We then let the thread go to sleep by calling QWaitCondition::wait().
serverPort = port;
mutex.unlock();
}
}
To copy to clipboard, switch view to plain text mode
Bookmarks