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));
|
QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
|
||||||
Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted");
|
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) {
|
if (that) {
|
||||||
that->weakref.ref();
|
that->weakref.ref();
|
||||||
return that;
|
return that;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <QtCore/private/qobject_p.h>
|
#include <QtCore/private/qobject_p.h>
|
||||||
#include <QRunnable>
|
#include <QRunnable>
|
||||||
|
#include <QSemaphore>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
@ -34,6 +35,7 @@ private slots:
|
|||||||
void disconnect();
|
void disconnect();
|
||||||
void castDuringDestruction();
|
void castDuringDestruction();
|
||||||
void threadSafety();
|
void threadSafety();
|
||||||
|
void raceCondition();
|
||||||
|
|
||||||
void qvariantCast();
|
void qvariantCast();
|
||||||
void constPointer();
|
void constPointer();
|
||||||
@ -529,6 +531,41 @@ void tst_QPointer::threadSafety()
|
|||||||
owner.wait();
|
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()
|
void tst_QPointer::qvariantCast()
|
||||||
{
|
{
|
||||||
QFile file;
|
QFile file;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user