LINUX.ORG.RU

Почему heap повреждается в qt примере ?

 , , , ,


0

1

Создаю 2 потока, один из них пишет в QTableWidget, другой читает, применяю QMutex.

Сам поток:

void work1::started_thread()
{
    qDebug() << "started_thread" << this << list.length();
    qDebug() << "work currentThreadId" << QThread::currentThreadId() << "reader" << reader;

    emit sendText("readerIs " + QString::number(reader) + " 0x" + QString::number((long long)QThread::currentThreadId(),16));
    for(int i=0;i<10000;i++)
    {
        mutex->lock();
       // qDebug() << i;
        for(int j=0;j<list.length();j++)
        {

            QTableWidgetItem * item = list.at(j);

            if(reader)
            {
                item->text();
             //   qDebug() << item->text();
                item->text();
            }
            else
            {
              //  qDebug() << "set" << i << j;
                item->setText(QString::number(i+j) + "_" + name);

            }






        }
        mutex->unlock();
      //  QThread::msleep(100);
    }

}

По кнопке вызываю оба треда: передаю в них list, который содержит QTableWidgetItem элементы таблицы, оба потока пользуются общим QMutex.

    w1->setList(list,"worker1",true,&mutex);
    w2->setList(list,"worker2",false,&mutex);
    emit operate1();
    emit operate2();

Получаю ошибку разрушения кучи:

Треад пишущий падает тут:

Thread 6 (Thread 12712.0x1304):
#0  0x00007ffdc946f1d3 in ntdll!RtlIsZeroMemory () from C:\WINDOWS\SYSTEM32\ntdll.dll
No symbol table info available.
#1  0x00007ffdc9477f92 in ntdll!RtlpNtSetValueKey () from C:\WINDOWS\SYSTEM32\ntdll.dll
No symbol table info available.
#2  0x00007ffdc947827a in ntdll!RtlpNtSetValueKey () from C:\WINDOWS\SYSTEM32\ntdll.dll
No symbol table info available.
#3  0x00007ffdc947df01 in ntdll!RtlpNtSetValueKey () from C:\WINDOWS\SYSTEM32\ntdll.dll
No symbol table info available.
#4  0x00007ffdc939dbc1 in ntdll!RtlAllocateHeap () from C:\WINDOWS\SYSTEM32\ntdll.dll
No symbol table info available.

......

#15 0x0000000067f14279 in QTableWidgetItem::setData (this=0x24e66bc0, role=<optimized out>, value=...) at itemviews\qtablewidget.cpp:1397
        roles = {d = 0x2871bf40}
        model = 0x24dd2800
        found = <optimized out>
#16 0x000000000040668a in QTableWidgetItem::setText (this=0x24e66bc0, atext=...) at C:/Qt/Qt5.12.0/5.12.0/mingw73_64/include/QtWidgets/qtablewidget.h:186
No locals.
#17 0x0000000000402a0d in work1::started_thread (this=0x1cfc8e60) at ..\TestCrashTable\work1.cpp:42
        item = 0x24e66bc0
        j = 43
        i = 39
        __PRETTY_FUNCTION__ = "void work1::started_thread()"

Тред читающий в этот момент висит на мьютексе:

Thread 5 (Thread 12712.0x413c):
#0  0x00007ffdc940cdf4 in ntdll!ZwWaitForSingleObject () from C:\WINDOWS\SYSTEM32\ntdll.dll
No symbol table info available.
#1  0x00007ffdc6b01a5e in WaitForSingleObjectEx () from C:\WINDOWS\System32\KernelBase.dll
No symbol table info available.
#2  0x00000000011e82b4 in QMutexPrivate::wait (this=this@entry=0x24ecbbc8, timeout=timeout@entry=-1) at thread/qmutex_win.cpp:64
No locals.
#3  0x00000000011e84a6 in QBasicMutex::lockInternal (this=0x87fd50, timeout=-1) at thread\qmutex.cpp:573
        copy = 0x24ecbbc8
        d = 0x24ecbbc8
        old_waiters = <optimized out>
#4  0x00000000011e8586 in QBasicMutex::lockInternal (this=0x47c) at thread\qmutex.cpp:489
No locals.
#5  0x00000000011e85f7 in QMutex::lock (this=<optimized out>) at thread\qmutex.cpp:227
        current = <optimized out>
#6  0x000000000040291a in work1::started_thread (this=0x1cfc7f10) at ..\TestCrashTable\work1.cpp:26
        i = 39
        __PRETTY_FUNCTION__ = "void work1::started_thread()"

Хотелось бы понять, почему падает поток.

Ты когда меняешь данные триггеришь обновление содержимого на экране. Это должно делаться из одного главного потока.

В qt же сделали сигналы/слоты чтобы данными швыряться в том числе и между разными потоками, а ты начал мьютексами обмазываться.

Передавай данные в основной поток через сигнал и там обновляй виджет.

Ну либо переходи на qtableview (view!, не widget) и делай свою модель, которая будет уметь обновляться/читаться из разных потоков. Сейчас же у тебя встроенная модель из qtablewidget. Очевидно она на такое не рассчитана.

ox55ff ★★★★★
()
Последнее исправление: ox55ff (всего исправлений: 1)
Ответ на: комментарий от dibr0v72

Я не назначал слоты QTableWidgetItem специально, возможно он сам и кидает сигналы

Кидает не он, а модель после изменения данных. Qtableview подписан на сигналы обновления модели. И подписан через прямое соединение сигналов. Получается у тебя конфликтуют два потока: твой пишущий и главный поток, в котором крутится цикл gui.

ox55ff ★★★★★
()
Ответ на: комментарий от dibr0v72

У тебя виджет является хранилищем информации раз уж другой поток читает из него. Это плохая архитектура. Виджет должен только отображать.

Делай отдельно модель и заменяй qtablewidget на qtableview. Вот модель и будет хранилищем. Её можешь мьютексами обмазать.

ox55ff ★★★★★
()

В книжках вообще пишут, что весь Qt GUI должен вертеться в главном потоке. Т.е. если у тебя 2 потока дрючат 1 виджет, ты уже делаешь что-то не так.

Так что да делай QTableView, к нему модель, а уж модель пусть с другими потоками данными перешвыривается через сигналы.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)