Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ QSharedData崩溃_C++_Multithreading_Qt_Qshareddata - Fatal编程技术网

C++ QSharedData崩溃

C++ QSharedData崩溃,c++,multithreading,qt,qshareddata,C++,Multithreading,Qt,Qshareddata,在我的Qt 5.2.0应用程序中,我遇到了一个罕见但相当一致的崩溃,我在诊断它时花了很多时间,但我相信它与QSharedData有关。应用程序是高度多线程的,这可能是问题的一部分 所讨论的课程在这里: class RouteData : public QSharedData { public: RouteData() : m_destAddress(0), m_valid(false), m_movingAverage(ROUTE_INITIAL_QUAL

在我的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);
其中m_lastRouteMap是一个
QMap

堆栈跟踪如下所示:

(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
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;
}
(gdb)其中
#QTimeZone::~QTimeZone()()中的0 0x00007fa297ced9a8来自/usr/local/trolletech/Qt-5.2.0/lib/libQt5Core.so.5
#1 0x00007fa297c96de5在QDateTime::~QDateTime()()中,来自/usr/local/trolletech/Qt-5.2.0/lib/libQt5Core.so.5
#RouteData中的2 0x0000000000464FB::~RouteData(this=0x7fa28c00b150,u in_chrg=)位于../libILS/libILS/Route.h:33
#QSharedDataPointer::operator=(此=0x7fa28c0e6420,o=…)中的3 0x0000000000600805
at/usr/local/trolledtech/Qt-5.2.0/include/QtCore/qshareddata.h:98
#在./libILS/Route.h:43处的Route::operator=(this=0x7fa28c0e6420)中的4 0x00000000005ff55b
#QMap::insert中的5 0x0000000000652f8e(this=0x7fa28c0880e8,akey=@0x7fa17c6feb44:25504,avalue=…)
at/usr/local/TROLTECH/Qt-5.2.0/include/QtCore/qmap.h:682
#ils::EmberGateway::ezspSendUnicast中的6 0x0000000000641b4b(此=0x7fa28c088090,indexOrDestination=25504,apsFrame=。。。,
libILS/Gateways/EmberGateway.cpp:909上的数据=…,路由=…)
#ils::EmberGateway::sendUnicast中的7 0x00000000006371d5(this=0x7fa28c088090,destAddress=25504,数组=…,路由=…)
在libILS/Gateways/EmberGateway.cpp:474
#网络控制器中的8 0x00000000005fadc4::sendMessageViaGateway(此=0x7fa28c03e9b0,消息=…)
在libILS/Controllers/NetworkController.cpp:1668
#NetworkController::dispatchMessage中的9 0x00000000005ed8f4(此=0x7fa28c03e9b0,pendingMessagePair=…)
在libILS/Controllers/NetworkController.cpp:913
#QtConcurrent::VoidStoredMemberFunctionPointerCall1::runFunctor中的10 0x0000000000604e2f(此函数=0x7fa23804ac60)
at/usr/local/Trolltech/Qt-5.2.0/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:410
#QtConcurrent::RunFunctionTask::run中的11 0x00000000005ff41e(此=0x7fa23804ac60)
at/usr/local/Trolltech/Qt-5.2.0/include/QtConcurrent/qtconcurrentrunbase.h:132
#12 0x00007fa297c55e52英寸??()来自/usr/local/Trolltech/Qt-5.2.0/lib/libQt5Core.so.5
#13 0x00007fa297c591c2英寸??()来自/usr/local/Trolltech/Qt-5.2.0/lib/libQt5Core.so.5
#14 0x00007fa297746f3a位于/lib64/libpthread.so.0的start_线程()中
#来自/lib64/libc.so.6的克隆()中的15 0x00007fa296c698fd
所以在#5我们正在做QMap::insert,在#4创建一个拷贝(通过Route“=”操作符)。在#3处,所讨论的Qt代码如下所示:

(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
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;
}
inlineqshareddatapointer&operator=(常量QSharedDataPointer&o){
如果(外径!=d){
如果(外径)
o、 d->ref.ref();
T*old=d;
d=外径;
if(old&&!old->ref.deref())
删除旧的;
}
归还*这个;
}
我们在dtor中针对一个
QDateTime
(实际上它是private
QTimeZone
成员)执行“delete old”和seg错误

我的
ezspSendUnicast()
方法可以在崩溃之前正常运行数十万次迭代。我不认为我在泄漏内存(根据valgrind)。我相信我传递给ezspSendUnicast()的路由对象受到了适当的互斥保护,但我可能遗漏了什么(但我认为
QSharedData
在任何情况下对于写时复制都是线程安全的)


任何关于如何解决这个问题的见解都将不胜感激

当通过
QSharedData指针
单独实例访问
QSharedData的实例时,实际上可以一次从多个线程访问,而且是安全的。共享数据指针将根据需要自动获取引用数据的副本

所以,只要您正在处理自己的
Route
对象实例,一切都很好。您不能使用对容器持有的元素的引用。您可以使用const引用来引用由容器持有的临时对象构造而成的临时对象,即新实例

Route r(...);
QMutexLocker l(&routeMapMutex);
routeMap.insert(key, r);
l.unlock();
r.setDestination(...);
QMutexLocker l(&routeMapMutex);
routeMap.insert(key, r);
l.unlock();
QMutexLocker l(&routeMapMutex);
Route r = routeMap[key];
l.unlock();
if (r.isValid()) ...
根据:

在共享的实例时,应使用正确的锁定 线程之间隐式共享类

在不持有锁的情况下访问隐式共享类的共享实例的引用是不正确的

您必须始终有一个新实例。您可以复制构造一个临时实例,然后通过常量引用传递它,例如作为函数调用中的参数传递

这适用于Qt 4和Qt 5中的所有隐式共享类——无论是来自Qt本身(所有容器!),还是您自己利用
QSharedDataPointer的设计

所以,这是正确的-您保留自己的实例

Route r(...);
QMutexLocker l(&routeMapMutex);
routeMap.insert(key, r);
l.unlock();
r.setDestination(...);
QMutexLocker l(&routeMapMutex);
routeMap.insert(key, r);
l.unlock();
QMutexLocker l(&routeMapMutex);
Route r = routeMap[key];
l.unlock();
if (r.isValid()) ...
同样,您也有自己的实例

Route r(...);
QMutexLocker l(&routeMapMutex);
routeMap.insert(key, r);
l.unlock();
r.setDestination(...);
QMutexLocker l(&routeMapMutex);
routeMap.insert(key, r);
l.unlock();
QMutexLocker l(&routeMapMutex);
Route r = routeMap[key];
l.unlock();
if (r.isValid()) ...
但这肯定是错误的,即使引用是const

QMutexLocker l(&routeMapMutex);
const Route & r = routeMap[key];
l.unlock();
if (r.isValid()) ...
但这是正确的,因为它是对临时实例的常量引用,其生命周期会根据需要延长。因此,您引用了一个只有您才能访问的新实例

QMutexLocker l(&routeMapMutex);
const Route & r = Route(routeMap[key]);
l.unlock();
if (r.isValid()) ...
这也是正确的,因为调用由互斥锁保护:

void fun(const Route &);
QMutexLocker l(&routeMapMutex);
fun(routeMap[key]);
l.unlock();
我的直觉是,在代码的某个地方,您可以访问对映射中的值的引用(而不是对临时值的const ref),而不必持有互斥体


同样可以想象的是,您有一些其他内存或线程错误,这些错误会在一个不相关的地方出现。

QSharedData
是线程安全的,但是
QMap
不是。您是否使用锁正确保护了insert?@Alexelishev
QSharedDataPointer
是线程安全的。就这样。它访问的数据不会神奇地变成线程安全的,一点也不会。好吧,这是有道理的。我认为发生的事情是这样的:我有一个由多个线程访问的路由的可变容器,比如说