我在我的 Qt 5.2.0 应用程序中有一个不常见但相当一致的崩溃,我有一个时间诊断,但相信与QSharedData
. 该应用程序是高度多线程的,这可能是问题的一部分。
有问题的课程在这里:
class RouteData : public QSharedData
{
public:
RouteData() :
m_destAddress(0),
m_valid(false),
m_movingAverage(ROUTE_INITIAL_QUALITY)
{ }
RouteData(const RouteData &other) :
QSharedData(other),
m_destAddress(other.m_destAddress),
m_addresses(other.m_addresses),
m_valid(other.m_valid),
m_movingAverage(other.m_movingAverage),
m_lastSuccess(other.m_lastSuccess),
m_lastFailure(other.m_lastFailure)
{ }
~RouteData() { }
quint16 m_destAddress;
QList<quint16> m_addresses;
bool m_valid;
double m_movingAverage;
QDateTime m_lastSuccess;
QDateTime m_lastFailure;
};
class Route
{
public:
Route()
{
d = new RouteData;
}
Route(quint16 destAddress)
{
d = new RouteData;
d->m_destAddress = destAddress;
}
Route(const Route &other) : d(other.d) {}
QString toString() const;
bool isValid() const { return d->m_valid; }
quint16 destAddress() const { return d->m_destAddress; }
QList<quint16> addressList() const { return d->m_addresses; }
quint32 length() const { return d->m_addresses.length(); }
double quality() const { return d->m_movingAverage; }
quint64 msecsSinceLastFailure() const;
void setDestination(quint16 dest) { d->m_destAddress = dest; }
void setAddressList(const QList<quint16> &addressList);
void markResult(bool success);
bool operator<(const Route& other) const;
bool operator==(const Route& other) const;
bool operator!=(const Route& other) const;
private:
QSharedDataPointer<RouteData> d;
};
Q_DECLARE_TYPEINFO(Route, Q_MOVABLE_TYPE);
崩溃发生在这里,将 Route 插入QMap
:
SendResult EmberGateway::ezspSendUnicast(quint16 indexOrDestination, ..., const Route& route)
{
...
if (route.isValid()) {
m_lastRouteMap.insert(indexOrDestination, route);
其中 m_lastRouteMap 是一个QMap<quint16, Route>
.
堆栈跟踪如下所示:
(gdb) where
#0 0x00007fa297ced9a8 in QTimeZone::~QTimeZone() () from /usr/local/Trolltech/Qt-5.2.0/lib/libQt5Core.so.5
#1 0x00007fa297c96de5 in QDateTime::~QDateTime() () from /usr/local/Trolltech/Qt-5.2.0/lib/libQt5Core.so.5
#2 0x00000000004644fb in RouteData::~RouteData (this=0x7fa28c00b150, __in_chrg=<optimized out>) at ../libILS/libILS/Route.h:33
#3 0x0000000000600805 in QSharedDataPointer<RouteData>::operator= (this=0x7fa28c0e6420, o=...)
at /usr/local/Trolltech/Qt-5.2.0/include/QtCore/qshareddata.h:98
#4 0x00000000005ff55b in Route::operator= (this=0x7fa28c0e6420) at ./libILS/Route.h:43
#5 0x0000000000652f8e in QMap<unsigned short, Route>::insert (this=0x7fa28c0880e8, akey=@0x7fa17c6feb44: 25504, avalue=...)
at /usr/local/Trolltech/Qt-5.2.0/include/QtCore/qmap.h:682
#6 0x0000000000641b4b in ils::EmberGateway::ezspSendUnicast (this=0x7fa28c088090, indexOrDestination=25504, apsFrame=...,
data=..., route=...) at libILS/Gateways/EmberGateway.cpp:909
#7 0x00000000006371d5 in ils::EmberGateway::sendUnicast (this=0x7fa28c088090, destAddress=25504, array=..., route=...)
at libILS/Gateways/EmberGateway.cpp:474
#8 0x00000000005fadc4 in NetworkController::sendMessageViaGateway (this=0x7fa28c03e9b0, message=...)
at libILS/Controllers/NetworkController.cpp:1668
#9 0x00000000005ed8f4 in NetworkController::dispatchMessage (this=0x7fa28c03e9b0, pendingMessagePair=...)
at libILS/Controllers/NetworkController.cpp:913
#10 0x0000000000604e2f in QtConcurrent::VoidStoredMemberFunctionPointerCall1<void, NetworkController, QPair<QSharedPointer<Message>, QTimer*>, QPair<QSharedPointer<Message>, QTimer*> >::runFunctor (this=0x7fa23804ac60)
at /usr/local/Trolltech/Qt-5.2.0/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:410
#11 0x00000000005ff41e in QtConcurrent::RunFunctionTask<void>::run (this=0x7fa23804ac60)
at /usr/local/Trolltech/Qt-5.2.0/include/QtConcurrent/qtconcurrentrunbase.h:132
#12 0x00007fa297c55e52 in ?? () from /usr/local/Trolltech/Qt-5.2.0/lib/libQt5Core.so.5
#13 0x00007fa297c591c2 in ?? () from /usr/local/Trolltech/Qt-5.2.0/lib/libQt5Core.so.5
#14 0x00007fa297746f3a in start_thread () from /lib64/libpthread.so.0
#15 0x00007fa296c698fd in clone () from /lib64/libc.so.6
所以在 #5 我们正在做 QMap::insert,在 #4 创建一个副本(通过 Route "=" 运算符)。在#3,有问题的 Qt 代码如下所示:
inline QSharedDataPointer<T> & operator=(const QSharedDataPointer<T> &o) {
if (o.d != d) {
if (o.d)
o.d->ref.ref();
T *old = d;
d = o.d;
if (old && !old->ref.deref())
delete old;
}
return *this;
}
QDateTime
我们正在为其中一个(实际上是私有QTimeZone
成员)在 dtor 中点击“删除旧”并进行分段故障。
我的ezspSendUnicast()
方法在崩溃之前可以正常运行数十万次迭代。我不认为我在泄漏内存(根据 valgrind)。我相信我传递给 ezspSendUnicast() 的 Route 对象受到了适当的互斥保护,但我可能错过了一些东西(但我认为QSharedData
无论如何写时复制都是线程安全的)。
任何有关如何解决此问题的见解将不胜感激!