PDA

View Full Version : Calling QSerialPort methods from two different threads



egzi
28th May 2015, 20:51
Hi.

I am trying to write a class that makes sync and async requests to some device on a serial port, but it always shows me worrisome
messages like:

QObject::killTimer: Timers cannot be stopped from another thread
QObject::startTimer: Timers cannot be started from another thread

For the sake of presentation I wrote a simple class (below). I know I can do it other ways but this way its much easier to implement communication timeouts, request repetition, received packet completion etc. It's also easy to implement sync methods, as I can just call directly internal blocking methods of object owned by worker thread (QSerialPort in this example).
There is no event loop in worker thread, threads are synchronized, so it should be perfectly safe to call syncWrite method from main thread, but then I get those messages. Is there any easy way out to solve this problem?

Thank you.


class SerialThread : public QThread
{
Q_OBJECT
public:
QMutex quit;

SerialThread()
{

}

~SerialThread()
{
quit.lock();
wait();
}

void asyncWrite(QByteArray data)
{
QMutexLocker locker(&mutex);
buffer = data;
}

bool syncWrite(QByteArray &data)
{
QMutexLocker locker(&mutex);
serial->write(data);
if(serial->waitForReadyRead(1000))
{
data = serial->readAll();
return true;
}
return false;
}

private:
QMutex mutex;
QSerialPort * serial;
QByteArray buffer;

virtual void run()
{
mutex.lock();
QSerialPort port;
serial = &port;

port.setPortName("COM10");
port.open(QSerialPort::ReadWrite);

while (quit.tryLock()) {
quit.unlock();

if(!buffer.isEmpty())
{
serial->write(buffer);
buffer.clear();
if(serial->waitForReadyRead(1000))
{
emit onRead(serial->readAll());
}
else
emit onError();
}


mutex.unlock();
msleep(10);
mutex.lock();
}
}
signals:
void onRead(QByteArray data);
void onError();

};

anda_skoa
29th May 2015, 08:36
so it should be perfectly safe to call syncWrite method from main thread

Only if you know for sure that none of the called code does anything thread specific.
Which seems not to be the case here.

You could implement the sync write in terms of doing an async write and then waiting for it to complete.

Btw, your async write is overwriting the shared buffer, if you call it twice in a row, only the second data packet will be sent.
Might be what you want of course.

Cheers,
_

egzi
31st May 2015, 00:01
You could implement the sync write in terms of doing an async write and then waiting for it to complete.
_

Then I would have to define variables which will hold results, some signaling method to wait for the results, its a pain in the ass and all that for each and every blocking method. That is how I will do that in the end, but I hoped for some more neat method. QT supposed to be easy threaded, but instead all those mechanisms just give me a headache. I have a feeling they are good just for incrementing ints (most examples on the net).
I wondered if I could use QTConcurrent::run and pass the thread in the thread pool. I will try when I get back my mood for qt programming.




Btw, your async write is overwriting the shared buffer, if you call it twice in a row, only the second data packet will be sent.
_

Yeah I know. It's just an example. Actually I have a blocking communication class which uses QSerialPort internally, that was easy to write. Now I want to implement an async methods but I want to have sync methods at the same time which leads me to the example-like wrapper which in turn gives me those error messages.

Thank you.

anda_skoa
31st May 2015, 09:53
Then I would have to define variables which will hold results

Depends.
If the calling thread can be allowed to further process events then it could "block" in a nested event loop.
Even when full blocking is required, it would mostly be a matter of chosing the "Task" structure accordingly.



some signaling method to wait for the results

Binary semaphore. Acquire in caller, release in worker.

Cheers,
_