2012-02-28 1 views
3

Довольно новый для потоковой передачи, и у меня есть этот QList, что потоки разделяют между ними. У всех у них есть собственное пространство, над которым они могут работать, и графический интерфейс (модель/представление) постоянно просматривают этот список. Затем я получаю этот крах, который указывает на QDataList.size(). Отладка на самом деле не помогает мне, так как я никогда не сталкивался с этой проблемой, если я перехожу к коду, и когда я пытаюсь скомпрометировать qList, нет никакой информации.Могут ли два потока читать из одного и того же QList одновременно?

Итак, мой вопрос: возможно ли получить размер Qlists и читать объекты одновременно? Объекты в списке являются потокобезопасными и не могут быть прочитаны/записаны разными потоками одновременно.

Получение «0xC0000005: место для обнаружения нарушения доступа 0xfeeefefa». который указывает мне: размер рядный Int() сопзЬ в qlist.h

Я иду через стек вызовов и нашел это:

QtCored4.dll!QListData::size() Line 98 + 0x11 bytes C++ 
QtNetworkd4.dll!QList<enum QNetworkReplyImplPrivate::InternalNotifications>::size() Line 137 + 0x10 bytes C++ 
QtNetworkd4.dll!QNetworkReplyImplPrivate::resumeNotificationHandling() Line 444 + 0xe bytes C++ 
QtNetworkd4.dll!QNetworkReplyImplPrivate::finished() Line 797 C++ 
QtNetworkd4.dll!QNetworkAccessBackend::finished() Line 313 C++ 
QtNetworkd4.dll!QNetworkAccessHttpBackend::replyFinished() Line 739 C++ 
QtNetworkd4.dll!QNetworkAccessHttpBackend::qt_static_metacall(QObject * _o, QMetaObject::Call _c, int _id, void * * _a) Line 86 + 0x8 bytes C++ 
QtCored4.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 525 + 0x1d bytes C++ 
QtCored4.dll!QObject::event(QEvent * e) Line 1195 + 0x14 bytes C++ 
QtGuid4.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 4550 + 0x11 bytes C++ 
QtGuid4.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3932 + 0x10 bytes C++ 
QtCored4.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 876 + 0x15 bytes C++ 
QtCored4.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 231 + 0x39 bytes C++ 
QtCored4.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1500 + 0xd bytes C++ 
QtCored4.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned int wp, long lp) Line 496 + 0x10 bytes C++ 

Каждый поток, имеющий менеджер сети, который делает networkRequest:

QThread ASSERT failure in QMutexLocker: "QMutex pointer is misaligned",

+0

Любая функция члена QList, которая не является 'const', может потенциально изменить ее состояние. –

+0

Вы пробовали синхронизацию с помощью блокировки? http://doc.trolltech.com/4.7/qreadwritelock.html – jdi

+0

различные потоки будут изменять объекты в списке, не добавляя или не удаляя из него объекты – chikuba

ответ

9

Я понимаю, что его можно предварительно выделить QList и пусть потоки работают на различных областях этого списка, но, на мой взгляд, я думаю, что его плохой образец для подражания.

Когда я работаю с Qt (я действительно работаю с PyQt, так как я программист на Python), я считаю, что лучше всего использовать механизм сигнала/слота, который предоставляется вам, и никогда не обмениваться памятью между потоками. Каждому потоку должны быть предоставлены собственные данные либо непосредственно при создании, либо через какое-то время через ожидающую очередь. Когда это делается с его работой или куском работы, он может выдавать сигнал с данными. У вас будет один обработчик, который подключается ко всем вашим потокам, чтобы слушать, что данные будут готовы.

Результат этого шаблона заключается в том, что вы не используете память, и вам не нужно так беспокоиться о блокировках, а просто ждать, пока рабочие сообщают, что их данные готовы, и один обработчик собирает и обновление основной модели.

Это, как говорится, вот еще одна ссылка на кого-то с помощью QList в общей памяти и испытывающего аварии, пока они не запер: http://developer.qt.nokia.com/forums/viewthread/13049

Я думаю, когда люди (включая меня) первый начать работать с нитью немедленного импульс просто использовать контейнеры так же, как и всегда. Но как только вы начинаете потоки, вы сразу же увеличиваете как сложность логики кодов, так и способность к ошибкам. Синхронизация разделяемой памяти - это один из способов приблизиться к ней, используя мьютексы для блокировки ресурсов до доступа. Но я думаю, что стоит упомянуть другой способ общения.

Googles Go язык был построен с одним из основных принципов бытия: «Не общаться путем обмена памяти, разделяемой памяти, передавая» http://golang.org/doc/codewalk/sharemem/

Go хотел рассмотреть этот вопрос на его основе, передавая память над объектами канала, которые напоминают сигнал/слот в Qt. Один компонент имеет эксклюзивный локальный доступ к памяти, а затем передает его другому компоненту по каналу. Это гарантирует, что у вас не будет условий гонки. В любом случае, просто подумал, что я буду придерживаться этой дополнительной ссылки, потому что я чувствую, что это очень важно для проблем с программированием нитей.

+1

отлично. Почувствуйте силу сигнала и слотов. – UmNyobe

+0

Да, я не уверен, могу ли я легко разбить данные, так как набор будет довольно большим, а индексы каждого объекта будут привязаны к индексу в модели (модели/представлении). Поэтому, если один объект изменен, сигнал будет отправлен в модель, которая уведомляет о том, какой объект (строка) только что изменился. Нет смысла изменять весь список. Я мог бы, по-моему, изменить основной список, вызвав model.setData – chikuba

+0

Интересно, почему у меня было два downvotes на этом. Кто-нибудь хочет прокомментировать? – jdi

3

Нет, они не могут Err, возможно/возможно.В документации говорится, что все функции QList являются только reentrant и не являются потокобезопасными. Теперь обычное чтение из общей структуры должно быть потокобезопасным, но в этом случае Qt имеет ясную документацию и исключений для чтения нет. Поэтому вы должны предположить, что это недопустимо и может привести к ошибкам.

Обратите внимание, что std::list не страдает этой проблемой и позволяет читать из нескольких потоков (запись, конечно же, должна быть эксклюзивной).

Обратите внимание, что в Qt-потоке в целом есть много особых случаев, мне было предложено написать «requirements for a threaded API», многие из которых Qt терпят неудачу. Частично это история, и часть этого имеет дело с различными аппаратными средствами, но в общем случае Qt-потоки должны обрабатываться специально.


Поскольку документы несовместимы (см. Комментарий), я быстро просмотрел исходный код QList. Простые функции, такие как «начало», «размер» и «первый», кажутся доступными только для чтения. Они не изменяют структуру данных. Таким образом, если они вызывают сбои, это связано с тем, что другой поток одновременно изменяет список.

+1

Арнольд указывает, что общие документы-хранилища действительно делают гарантию только для чтения. Можно было бы предположить, что это применимо к Qlist, но документы, таким образом, несовместимы. –

+1

Я нашел проблему. Это связано с тем, что Networkreply и Qt проверяют его размер, хотя он должен был быть использован и готов к удалению к тому времени, но я думаю, что нет – chikuba

Смежные вопросы