6

I am using QBuffer in ReadWrite mode. One worker QThread pushes data in the buffer and another QThread reads from it.

Does QBuffer guarantee thread-safety or do I need to derive from QBuffer and add mutex stuff?

S B
  • 8,134
  • 10
  • 54
  • 108
  • You have only one pos(), so you would need to seek() and read() or write() inside a single critical section. Also, read()/write() should probably block if the buffer is empty/full? That's all quite different from QBuffer/QIODevice semantics and deserves its own class. – Frank Osterfeld Dec 13 '12 at 19:44
  • 1
    A QBuffer is not a pipe. It is simply not suited for your use, threads or not! The way you use it will eventually run out of memory, since the buffer can only grow, never shrink. If you want a class that presents two QIODevices, like ends of a pipe, you need to create your own. You can also reuse `QRingBuffer` (`#include `), but access to it has to be mutex-protected. – Kuba hasn't forgotten Monica Feb 08 '14 at 00:52
  • What you are *really* looking for is called a [lock-free queue](http://stackoverflow.com/questions/871234/circular-lock-free-buffer) - look at the most upvoted answer, it has excellent references. – Kuba hasn't forgotten Monica Feb 08 '14 at 00:53

5 Answers5

9

To quote Mark Summerfield's book C++ GUI Programming with Qt 4:

Qt's thread-safe classes include QMutex, QMutexLocker, QReadWriteLock, QReadLocker, QWriteLocker, QSemaphore, QThreadStorage, and QWaitCondition. In addition, parts of the QThread API and several other functions are thread-safe, notably QObject::connect(), QObject::disconnect(), QCoreApplication::postEvent(), and QCoreApplication::removePostedEvents().

Qt expects that you will use locking mechanisms around most of it's classes. The docs will say "All functions are thread-safe" if they are, and the individual functions will also specify "is thread-safe".

Notes on Qt Classes

Many Qt classes are reentrant, but they are not made thread-safe, because making them thread-safe would incur the extra overhead of repeatedly locking and unlocking a QMutex. For example, QString is reentrant but not thread-safe. You can safely access different instances of QString from multiple threads simultaneously, but you can't safely access the same instance of QString from multiple threads simultaneously (unless you protect the accesses yourself with a QMutex).

Some Qt classes and functions are thread-safe. These are mainly the thread-related classes (e.g. QMutex) and fundamental functions (e.g. QCoreApplication::postEvent()).

Because QBuffer is a direct subclass of QIODevice I would especially expect it not to be thread-safe, but there are container classes that are thread-safe for read-access, but would require locking for write access:

Container Classes

The container classes are implicitly shared, they are reentrant, and they are optimized for speed, low memory consumption, and minimal inline code expansion, resulting in smaller executables. In addition, they are thread-safe in situations where they are used as read-only containers by all threads used to access them.

jdi
  • 90,542
  • 19
  • 167
  • 203
2

QBuffer isn't the best way to communicate between threads as writing to it makes the buffer grows, but reading from it doesn't delete the data at the beginning.

You could instead use signal/slot with a QByteArray parameter, use QLocalSocket or write a thread-safe ring buffer class derived from QIODevice yourself.

alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • Very good point. Yes, I ended up deriving from `QIODevice` with my custom memory management and thread-safety locks. Also, for those who might be interested in going this route and like me if you need to prioritize reads over writes or the other way, consider using `QReadWriteLock` instead of `QMutex` when implementing thread safety – S B Dec 17 '12 at 11:23
1

That extends QIODevice, and the documentation there states that all methods on QIODevice are reentrant, but doesn't specify any thread safety on top of that. Given that QBuffer doesn't mention anything more I expect that QBuffer is not thread safe.

http://qt-project.org/doc/qt-4.8/qiodevice.html

Herms
  • 37,540
  • 12
  • 78
  • 101
0

The simplest way of communicating between threads in Qt is by posting events to the other thread's event queue. This assumes that the other thread spins an event loop. It only needs to spin it periodically where you'd ordinarily check for new data etc.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • How dare you, sir, give such simple advices to those seeking sophistication?? A sure downvote! – mlvljr Feb 07 '14 at 22:27
0

As several other posters have pointed out, QBuffer is the wrong tool for the job, regardless of thread safety issues.

Is there an intra-process local pipe in Qt? describes a QIODevice based FIFO queue that would be more appropriate for the intended purpose (though it doesn't include any thread safety mechanism)

Richard Lang
  • 456
  • 4
  • 15