Can two threads read from the same QList at the same time?

帅比萌擦擦* 提交于 2019-12-30 10:26:09

问题


Pretty new to threading and I have this QList that the threads share between them. They all have their own space that they can work on, and the GUI (the model/view) access this list constantly. I then get this crash which points to QDataList.size(). The debugging doesn't really help me since I never come across this issue if I step through the code and when I'm trying to what qList that's crashing, there's no info available.

So, my question is: Is it possible to get the Qlists size and read objects at the same time? The objects in the list are thread safe and cant be read/write by different threads at the same time.

Getting "0xC0000005: Access violation reading location 0xfeeefefa." which points me to: inline int size() const in qlist.h

I walk through the call stack and found this:

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++

Every thread is having a network manager that does a networkRequest:

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


回答1:


I realize that its possible to pre-allocate a QList and let threads operate on different areas of that list, but in my opinion I think its a bad pattern to follow.

When I work with Qt (I actually work with PyQt since I'm a python programmer), I feel its best to make use of the signal/slot mechanism that is provided to you and never share memory between threads. Each thread should be given its own data either directly at creation, or over time through a queue that is waits on. When it is done with its work or a chunk of work it can emit a signal with the data. You would have a single handler that connects to all of your threads to listen for data to be ready.

The result of this pattern is that you aren't sharing memory and you don't have to worry so much about locks, but rather just waiting for workers to signal their data is ready, and a single handler is collecting and updating the main model.

That being said, here is another reference of someone using a QList as shared memory and experiencing crashes until they locked it: http://developer.qt.nokia.com/forums/viewthread/13049

I think when people (myself included) first start working with thread the immediate impulse is to just use containers the same way they always have. But once you start threading you immediately already increase both the complication of the codes logic as well as the capacity for bugs. Synchronization of shared memory is one way to approach it, using mutexes to lock resources before access. But I think its worth mentioning another way which is communicating.

Googles Go language was built with one of its core principles being: "Dont communicate by sharing memory; share memory by communicating" http://golang.org/doc/codewalk/sharemem/

Go wanted to address this issue at its core by communicating memory over channel objects, which resemble signal/slot in Qt. One component has exclusive local access to memory and then pass it along to another component over a channel. This gurantees you wont have race conditions. Anyways just thought I would tack on this extra reference because I feel its very relevant to thread programming issues.




回答2:


No, they can't Err, maybe/probably. The documentation says that all QList functions are only reentrant, and not thread-safe. Now, normally reading from a shared structure should be thread-safe, but in this case Qt has explicit documentation and there is no exception made for reading. You therefore have to assume that it is not allowed and may result in errors.

Note that a std::list does not suffer from this problem and allows reading from multiple threads (writing must of course still be exclusive).

Note that Qt threading overall has a lot of special cases, it is was prompted me to write "requirements for a threaded API", many of which Qt fails. Part of this is history, and part of this is dealing with a variety of hardware, but in general Qt threading must be treated specially.


Since the docs are not consistent (see comment) I did a quick review of the QList source code. Simple functions like "begin", "size" and "first" do appear to be read-only. They do not modify the data structure. Thus if they are causing a crash it is because some other thread is modifying the list at the same time.



来源:https://stackoverflow.com/questions/9476045/can-two-threads-read-from-the-same-qlist-at-the-same-time

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!