diff options
-rw-r--r-- | doc/src/snippets/threads/threads.cpp | 9 | ||||
-rw-r--r-- | src/corelib/thread/qthreadstorage.cpp | 47 | ||||
-rw-r--r-- | src/corelib/thread/qthreadstorage.h | 13 | ||||
-rw-r--r-- | tests/auto/qthreadstorage/tst_qthreadstorage.cpp | 74 |
4 files changed, 104 insertions, 39 deletions
diff --git a/doc/src/snippets/threads/threads.cpp b/doc/src/snippets/threads/threads.cpp index d8d1270..d16c398 100644 --- a/doc/src/snippets/threads/threads.cpp +++ b/doc/src/snippets/threads/threads.cpp @@ -93,15 +93,12 @@ private: typedef int SomeClass; //! [7] -QThreadStorage<QCache<QString, SomeClass> *> caches; +QThreadStorage<QCache<QString, SomeClass> > caches; void cacheObject(const QString &key, SomeClass *object) //! [7] //! [8] { - if (!caches.hasLocalData()) - caches.setLocalData(new QCache<QString, SomeClass>); - - caches.localData()->insert(key, object); + caches.localData().insert(key, object); } void removeFromCache(const QString &key) @@ -110,7 +107,7 @@ void removeFromCache(const QString &key) if (!caches.hasLocalData()) return; - caches.localData()->remove(key); + caches.localData().remove(key); } //! [9] diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp index 2222427..8df6f39 100644 --- a/src/corelib/thread/qthreadstorage.cpp +++ b/src/corelib/thread/qthreadstorage.cpp @@ -216,19 +216,18 @@ void QThreadStorageData::finish(void **p) QThreadStorage is a template class that provides per-thread data storage. - \e{Note that due to compiler limitations, QThreadStorage can only - store pointers.} - The setLocalData() function stores a single thread-specific value for the calling thread. The data can be accessed later using - localData(). QThreadStorage takes ownership of the data (which - must be created on the heap with \c new) and deletes it when the - thread exits, either normally or via termination. + localData(). The hasLocalData() function allows the programmer to determine if data has previously been set using the setLocalData() function. This is also useful for lazy initializiation. + If T is a pointer type, QThreadStorage takes ownership of the data + (which must be created on the heap with \c new) and deletes it when + the thread exits, either normally or via termination. + For example, the following code uses QThreadStorage to store a single cache for each thread that calls the cacheObject() and removeFromCache() functions. The cache is automatically @@ -242,9 +241,6 @@ void QThreadStorageData::finish(void **p) \list - \o As noted above, QThreadStorage can only store pointers due to - compiler limitations. - \o The QThreadStorage destructor does not delete per-thread data. QThreadStorage only deletes per-thread data when the thread exits or when setLocalData() is called multiple times. @@ -280,8 +276,11 @@ void QThreadStorageData::finish(void **p) /*! \fn bool QThreadStorage::hasLocalData() const - Returns true if the calling thread has non-zero data available; - otherwise returns false. + If T is a pointer type, returns true if the calling thread has + non-zero data available. + + If T is a value type, returns wether the data has already been + constructed by calling setLocalData or localData. \sa localData() */ @@ -292,10 +291,8 @@ void QThreadStorageData::finish(void **p) Returns a reference to the data that was set by the calling thread. - Note: QThreadStorage can only store pointers. This function - returns a reference to the pointer that was set by the calling - thread. The value of this reference is 0 if no data was set by - the calling thread, + If no data has been set, this will create a default constructed + instance of type T. \sa hasLocalData() */ @@ -306,10 +303,6 @@ void QThreadStorageData::finish(void **p) Returns a copy of the data that was set by the calling thread. - Note: QThreadStorage can only store pointers. This function - returns a pointer to the data that was set by the calling thread. - If no data was set by the calling thread, this function returns 0. - \sa hasLocalData() */ @@ -319,19 +312,9 @@ void QThreadStorageData::finish(void **p) Sets the local data for the calling thread to \a data. It can be accessed later using the localData() functions. - If \a data is 0, this function deletes the previous data (if - any) and returns immediately. - - If \a data is non-zero, QThreadStorage takes ownership of the \a - data and deletes it automatically either when the thread exits - (either normally or via termination) or when setLocalData() is - called again. - - Note: QThreadStorage can only store pointers. The \a data - argument must be either a pointer to an object created on the heap - (i.e. using \c new) or 0. You should not delete \a data - yourself; QThreadStorage takes ownership and will delete the \a - data itself. + If T is a pointer type, QThreadStorage takes ownership of the data + and deletes it automatically either when the thread exits (either + normally or via termination) or when setLocalData() is called again. \sa localData(), hasLocalData() */ diff --git a/src/corelib/thread/qthreadstorage.h b/src/corelib/thread/qthreadstorage.h index 6264674..475d20d 100644 --- a/src/corelib/thread/qthreadstorage.h +++ b/src/corelib/thread/qthreadstorage.h @@ -91,6 +91,11 @@ inline void qThreadStorage_setLocalData(QThreadStorageData &d, T **t) { (void) d.set(*t); } +template <typename T> +inline +void qThreadStorage_deleteData(void *d, T **) +{ delete static_cast<T *>(d); } + // value-based specialization template <typename T> inline @@ -114,6 +119,12 @@ inline void qThreadStorage_setLocalData(QThreadStorageData &d, T *t) { (void) d.set(new T(*t)); } +template <typename T> +inline +void qThreadStorage_deleteData(void *d, T *) +{ delete static_cast<T *>(d); } + + // MOC_SKIP_END #endif @@ -126,7 +137,7 @@ private: Q_DISABLE_COPY(QThreadStorage) static inline void deleteData(void *x) - { delete static_cast<T>(x); } + { qThreadStorage_deleteData(x, reinterpret_cast<T*>(0)); } public: inline QThreadStorage() : d(deleteData) { } diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp index 54f8bd9..90e0311 100644 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp +++ b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp @@ -78,6 +78,7 @@ private slots: void ensureCleanupOrder(); void QTBUG13877_crashOnExit(); void QTBUG14579_leakInDestructor(); + void valueBased(); }; class Pointer @@ -318,6 +319,7 @@ public: static QBasicAtomicInt count; inline SPointer() { count.ref(); } inline ~SPointer() { count.deref(); } + inline SPointer(const SPointer &other) { count.ref(); } }; QBasicAtomicInt SPointer::count = Q_BASIC_ATOMIC_INITIALIZER(0); @@ -382,5 +384,77 @@ void tst_QThreadStorage::QTBUG14579_leakInDestructor() QCOMPARE(int(SPointer::count), c); } +void tst_QThreadStorage::valueBased() +{ + struct Thread : QThread { + QThreadStorage<SPointer> &tlsSPointer; + QThreadStorage<QString> &tlsString; + QThreadStorage<int> &tlsInt; + + int someNumber; + QString someString; + Thread(QThreadStorage<SPointer> &t1, QThreadStorage<QString> &t2, QThreadStorage<int> &t3) + : tlsSPointer(t1), tlsString(t2), tlsInt(t3) { } + + void run() { + /*QVERIFY(!tlsSPointer.hasLocalData()); + QVERIFY(!tlsString.hasLocalData()); + QVERIFY(!tlsInt.hasLocalData());*/ + SPointer pointercopy = tlsSPointer.localData(); + + //Default constructed values + QVERIFY(tlsString.localData().isNull()); + QCOMPARE(tlsInt.localData(), 0); + + //setting + tlsString.setLocalData(someString); + tlsInt.setLocalData(someNumber); + + QCOMPARE(tlsString.localData(), someString); + QCOMPARE(tlsInt.localData(), someNumber); + + //changing + tlsSPointer.setLocalData(SPointer()); + tlsInt.localData() += 42; + tlsString.localData().append(QLatin1String(" world")); + + QCOMPARE(tlsString.localData(), (someString + QLatin1String(" world"))); + QCOMPARE(tlsInt.localData(), (someNumber + 42)); + + // operator= + tlsString.localData() = QString::number(someNumber); + QCOMPARE(tlsString.localData().toInt(), someNumber); + } + }; + + QThreadStorage<SPointer> tlsSPointer; + QThreadStorage<QString> tlsString; + QThreadStorage<int> tlsInt; + + int c = SPointer::count; + + Thread t1(tlsSPointer, tlsString, tlsInt); + Thread t2(tlsSPointer, tlsString, tlsInt); + Thread t3(tlsSPointer, tlsString, tlsInt); + t1.someNumber = 42; + t2.someNumber = -128; + t3.someNumber = 78; + t1.someString = "hello"; + t2.someString = "trolltech"; + t3.someString = "nokia"; + + t1.start(); + t2.start(); + t3.start(); + + QVERIFY(t1.wait()); + QVERIFY(t2.wait()); + QVERIFY(t3.wait()); + + QCOMPARE(c, int(SPointer::count)); + +} + + QTEST_MAIN(tst_QThreadStorage) #include "tst_qthreadstorage.moc" |