【问题标题】:Is it safe to draw three separate QImages in three separate QThreads?在三个单独的 QThread 中绘制三个单独的 QImage 是否安全?
【发布时间】:2023-09-30 22:15:01
【问题描述】:

我有一个 QMainWindow,其中包含三个小部件,这些小部件被提升为包含子类 QThread 的类。他们每个人都在其相应的 qthread 中绘制本地 QImage,一旦绘制该信号就会发送一个信号,然后通过从插槽调用 update(mandlebrot 示例)进行渲染。这是安全的还是危险的?他们不共享任何数据,至少没有我正在生成的数据,并且想知道他们可以共享哪些超出我的编码范围的数据,即由 Qt 自动生成的数据。

【问题讨论】:

  • gtk 不属于这个问题。

标签: multithreading qt thread-safety widget qthread


【解决方案1】:

来自the documentation

QPainter 可用于在 QImage、QPrinter 和 QPicture 绘图设备上绘图。不支持在 QPixmaps 和 QWidgets 上绘画。在 Mac OS X 上,如果您从 GUI 线程外部打印,则不会显示自动进度对话框。

任何数量的线程都可以在任何给定时间绘制,但是一次只能有一个线程可以在给定的绘制设备上绘制。换句话说,如果两个线程分别绘制到不同的 QImage 上,则两个线程可以同时绘制,但是两个线程不能同时绘制到同一个 QImage 上。

请注意,在不支持 FontConfig 的 X11 系统上,Qt 无法在 GUI 线程之外渲染文本。您可以使用 QFontDatabase::supportsThreadedFontRendering() 函数来检测是否可以在 GUI 线程之外使用字体渲染。

因此,只要您注意 X11 上的字体问题,就不要使用任何像素图或光标(它们是作为像素图实现的),也不要尝试同时从多个线程...它应该可以工作。

请注意,在 Mandelbrot 示例中,QImage 在信号上按值传递(隐式共享),这意味着如果任一线程尝试写入,它将获得自己的副本。

【讨论】:

  • 好的,这些是我遵循的指导方针,但您是否预见到 GDB 在这方面有任何问题?在 qthread 中使用 QList 是否安全?
  • 调试多线程代码总是比单线程更棘手,但您正在绘制的事实并不会改变这一点。 Qt 数据结构像 QList 是 reentrant 但不是 thread-safe...如果可以有多个线程来锁定它们,则必须使用 QReadWriteLock 或 QMutex 锁定它们同时获得同一个 QList。见:doc.trolltech.com/4.6/threads-reentrancy.html
  • 我在以下代码中看到了 seg 错误:mediafire.com/?mwjlm3yltej 该类没有得到线程外任何东西访问的任何数据成员,只有当我放置断点时才会出现 seg 错误.我想认为这是 gdb 的错,但这很少见。我在运行时从来没有遇到过段错误。如果我复制该类的源代码三遍并将它用于每个对象实例,我不会得到这个段错误。当我一步一步编写代码时,它没有执行并重新开始(但在不同的线程中)所以我认为 gdb 对所有这些感到困惑。
  • 这是在运行函数中,如果代码看起来低级,即如果我不放置 QLists 之类的对象,它似乎不会发生。我所做的只是以 mandlebrot 为例,将 QMainWindow 中的 3 个小部件提升为 mandlebrot,删除在 run() 中绘制 QImage 的代码,并将其替换为一个简单的函数调用,它发生在该函数调用中。如果你能看一下,如果我不明白,那就太好了。
  • 好吧,我不会编译和调试你的代码! :) 但是,如果调试器没有帮助找到确凿的证据,那么您可以尝试以下方法:如果您的 something() 函数只是一个 while() 循环,并且计数到某个大数字,那么看看您是否仍然遇到问题.如果没有,请继续添加位,直到找出导致它的代码段。
最近更新 更多