[英]Design Pattern, Qt Model/View and multiple threads
I am creating an application which displays the market data and uses it in some other forms too. 我正在创建一个显示市场数据的应用程序,并以其他形式使用它。 I store market data in a map say
std::map<tickerId, StockData>
. 我将市场数据存储在地图中,例如
std::map<tickerId, StockData>
。 Let me give one used case of how this map can be used. 让我举一个关于如何使用这个地图的例子。
updatePrice(tickerId, latestPrice)
updatePosition(tickerId, price)
and updateStockScreen(tickerId, price)
. updatePosition(tickerId, price)
和updateStockScreen(tickerId, price)
。 Also, separting Gui updates from position update is important as GUI is not the main strength of the application. Some references to useful books are appreciated too. 对有用书籍的一些参考也受到赞赏。
I am new and trying to achieve too much with my little knowledge so forgive me if I have asked stupid/ill-formed questions. 我是新人,并试图通过我的小知识实现太多,所以如果我问过愚蠢/形成错误的问题,请原谅我。
Thanks Shiv 谢谢Shiv
It sounds conceptually like you want the model on one thread and the view on another, which I looked into at one point. 这听起来在概念上就像你想要一个线程上的模型和另一个线程上的视图,我在一个点上看到了。
If so...and your model is read-only through the view widget then yes, you have to lock. 如果是这样......并且您的模型通过视图小部件是只读的,那么是的,您必须锁定。 I'd argue that doing so undermines the elegance of the "decoupling" provided by the model/view separation.
我认为这样做会破坏模型/视图分离所提供的“解耦”的优雅。 But it could be made to work.
但它可以成功。
However...if your model is read-write through the view it's not possible to do correctly at all because of the queued nature of the notification slots. 但是...如果你的模型是通过它不可能做到正确的,因为在所有的通知插槽排队性质的观点读写。 Here's an archive of a mailing list conversation I had on the qt-interest mailing list on the topic:
这是我在qt-interest邮件列表上关于该主题的邮件列表对话的存档:
http://blog.hostilefork.com/qt-model-view-different-threads/ http://blog.hostilefork.com/qt-model-view-different-threads/
"The short version is that I don't think it's feasible for a Model to
“简短的版本是我认为模型不可行
be modified on a non-GUI thread...regardless of whether the model's在非GUI线程上进行修改......无论模型是否正确
data has been protected with read/write locks.数据已通过读/写锁保护。 If what I'm gathering
如果我正在收集
is correct, then Qt should probably have an assert that a model and是正确的,然后Qt应该有一个断言模型和
its view have the same thread affinity (it doesn't seem to do that now)"它的视图具有相同的线程亲和力(现在似乎没有这样做)“
A subsequent unit test by a KDE developer verified this. KDE开发人员进行的后续单元测试验证了这一点。
I feel the best way to work around this is to keep the model and the view on the same thread, and only modify the model in the GUI thread. 我觉得解决这个问题的最好方法是将模型和视图保持在同一个线程上,并且只修改GUI线程中的模型。 So if the worker thread wishes to change it then it should use a signal.
因此,如果工作者线程希望更改它,那么它应该使用信号。
Whether the worker needs to keep their own copy of the data from which the model was created (or if it needs to get notifications to keep that up to date when the user changes the model through the view) depends on your app. 工作者是否需要保留自己创建模型的数据副本(或者当用户通过视图更改模型时是否需要通知以使其保持最新)取决于您的应用程序。 If I understand you correctly, it sounds like like you could probably get away with just ferrying the updates through signal/slots and forgetting them on the worker...
如果我理解正确的话,听起来好像你可能只是通过信号/插槽传送更新而忘记工作人员......
I learned another potential problem today, the hard way, even if the model was read only. 即使模型是只读的,我今天也学到了另一个潜在的问题。 I use another thread to modify the data in the model (actually, my program is over 20 threads, and they all play nice), which then a Qt timer updates.
我使用另一个线程来修改模型中的数据(实际上,我的程序超过20个线程,它们都很好),然后Qt计时器更新。 This works very well, but there is a problem I fell into, which is:
这很有效,但我遇到了一个问题,那就是:
You cannot lock between rowCount
/ columnCount
and data()
. 您无法在
rowCount
/ columnCount
和data()
之间进行锁定。
Qt works sequentially, meaning that in human language, it'll ask "how big are you", and then ask "what data do you have at this position", and these are prone to break. Qt按顺序工作,这意味着在人类语言中,它会问“你有多大”,然后问“你在这个位置有什么数据”,这些很容易破解。
Consider: 考虑:
int FilesQueue::rowCount(const QModelIndex &/*parent*/) const
{
std::lock_guard<decltype(mainQueueMutex)> lg(mainQueueMutex);
return filesQueue.size();
}
QVariant FilesQueue::data(const QModelIndex &index, int role) const
{
std::lock_guard<decltype(mainQueueMutex)> lg(mainQueueMutex);
if ( role == Qt::DisplayRole) {
return filesQueue[index.row()]->getFilename();
}
}
Qt will do the calls like this: Qt会做这样的调用:
//...
obj->rowCount();
obj->data(...);
//...
And I had assertion failure all over the place because simply, between rowCount()
and data()
, there was a thread that was changing the size of the data! 而且我在整个地方都有断言失败,因为简单地说,在
rowCount()
和data()
,有一个线程正在改变数据的大小! It broke the program. 它打破了这个计划。 So this was happening:
所以这发生了:
//...
obj->rowCount();
//another thread: filesQueue.erase(...)
obj->data(...);
//...
My solution to the problem is to verify the size, again, in the data() method: 我对此问题的解决方案是再次在data()方法中验证大小:
QVariant FilesQueue::data(const QModelIndex &index, int role) const
{
std::lock_guard<decltype(mainQueueMutex)> lg(mainQueueMutex);
//solution is here:
if(static_cast<int>(filesQueue.size()) <= index.row())
return QVariant();
if ( role == Qt::DisplayRole) {
return filesQueue[index.row()]->getFilename();
}
}
and there goes 3 hours of my life I'll never get back :-) 我生命中有3个小时我永远不会回来:-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.