QPointer: fix data race on ExternalRefCountData
The creation of the ExternalRefCountData was published with testAndSetOrdered() but the loadRelaxed() would only load the pointer value, not the effects of the constructor. Pick-to: 6.9 6.8 6.5 Fixes: QTBUG-135640 Change-Id: I3acbc51e763e8a291be3f7036e0d9cd3965a2ce8 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
parent
22d4f117bd
commit
253f34082f
@ -1531,7 +1531,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
|
||||
QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
|
||||
Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted");
|
||||
|
||||
ExternalRefCountData *that = d->sharedRefcount.loadRelaxed();
|
||||
ExternalRefCountData *that = d->sharedRefcount.loadAcquire();
|
||||
if (that) {
|
||||
that->weakref.ref();
|
||||
return that;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <QtCore/private/qobject_p.h>
|
||||
#include <QRunnable>
|
||||
#include <QSemaphore>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <QPointer>
|
||||
@ -34,6 +35,7 @@ private slots:
|
||||
void disconnect();
|
||||
void castDuringDestruction();
|
||||
void threadSafety();
|
||||
void raceCondition();
|
||||
|
||||
void qvariantCast();
|
||||
void constPointer();
|
||||
@ -529,6 +531,41 @@ void tst_QPointer::threadSafety()
|
||||
owner.wait();
|
||||
}
|
||||
|
||||
void tst_QPointer::raceCondition()
|
||||
{
|
||||
const int NUM_THREADS = 20;
|
||||
const int ITERATIONS_PER_THREAD = 10;
|
||||
|
||||
QSemaphore startSemaphore;
|
||||
|
||||
QObject targetObject;
|
||||
|
||||
std::vector<std::unique_ptr<QThread>> threads;
|
||||
threads.reserve(NUM_THREADS);
|
||||
|
||||
for (int i = 0; i < NUM_THREADS; ++i) {
|
||||
QThread *thread =
|
||||
QThread::create([&startSemaphore, &targetObject, ITERATIONS_PER_THREAD]() {
|
||||
startSemaphore.acquire();
|
||||
|
||||
for (int j = 0; j < ITERATIONS_PER_THREAD; ++j) {
|
||||
QPointer<QObject> pointer(&targetObject);
|
||||
Q_UNUSED(pointer);
|
||||
}
|
||||
});
|
||||
|
||||
threads.emplace_back(thread);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
QTest::qWait(100);
|
||||
startSemaphore.release(NUM_THREADS);
|
||||
|
||||
for (const auto &thread : threads) {
|
||||
QVERIFY(thread->wait(30000));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QPointer::qvariantCast()
|
||||
{
|
||||
QFile file;
|
||||
|
Loading…
x
Reference in New Issue
Block a user