树莓派上 SDL 1.2 的奇怪线程死锁

Posted

技术标签:

【中文标题】树莓派上 SDL 1.2 的奇怪线程死锁【英文标题】:strange thread deadlock with SDL 1.2 on raspberry pi 【发布时间】:2013-12-02 06:03:42 【问题描述】:

我一直在使用一个简单的双线程应用程序,其中两个线程同时运行。每个线程将图形(三角形/矩形)绘制到屏幕的预定义且互斥的部分。也就是说,两个线程永远不会在彼此的屏幕空间中写入。

程序运行了很长时间,比如说5个小时左右,主线程一直在运行,但是另一个线程却死机了(虽然它没有死)。

我在 backtrace o/p 中得到了这个,我猜这显示了一个死锁。

Thread 2 (Thread 0xb542f440 (LWP 2142)):
#0  0xb6e83258 in __lll_lock_wait ()
   from /lib/arm-linux-gnueabihf/libpthread.so.0
#1  0xb6e7de38 in pthread_mutex_lock ()
   from /lib/arm-linux-gnueabihf/libpthread.so.0
#2  0xb6ef8de4 in SDL_mutexP ()
   from /usr/lib/arm-linux-gnueabihf/libSDL-1.2.so.0
#3  0xb6ef4058 in ?? () from /usr/lib/arm-linux-gnueabihf/libSDL-1.2.so.0
#4  0xb6ef4058 in ?? () from /usr/lib/arm-linux-gnueabihf/libSDL-1.2.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

真的是 libSDL1.2 的问题吗?我是否必须为我正在做的每个 SDL_Blit/或其他使用 SDL 的操作编写明确的用户定义互斥锁?还是我缺少其他东西?我该如何解决这个问题?

我正在使用: Raspberry Pi 中可用的 libSDL1.2 libPthreads libSDL_ttf

编辑:线程 2 互斥锁的 gdb 跟踪:

(gdb) p *(pthread_mutex_t*) 0xb542ed38 $3 = _数据 = _lock = 39257160, __count = 1048617, __owner = 0, __kind = 7078021,_nusers = 0,_spins = 0,_list = _next = 0x0, __size = "H\004W\002)\000\020\000\000\000\000\000\205\000l\000\000\000\000\000\000\000\000", __align = 39257160

如果您需要更多信息,请告诉我。

【问题讨论】:

【参考方案1】:

此方法仅适用于软件表面(无硬件加速)。对于硬件表面,它充其量只能锁定和等待——这无论如何都没有性能优势;在糟糕的情况下(通过快速查看 SDL 源代码判断)它可能会以 SDL_LockSurface 工作原理的简单逻辑而以糟糕的方式结束。

我什至不确定你的外部互斥锁是否会有所帮助,因为硬件加速图形访问几乎总是被锁定到一个线程(OpenGL 就是一个很好的例子 - 每个线程都有自己独立的绘图上下文)。

简而言之,我认为你没有理由使用两个线程进行绘图,但无论如何不能保证它是线程安全的。

【讨论】:

是的,我直接在 SDL HW 表面上进行 blitting。但是,我不明白,它怎么会在 3,29,00,000 次调用后冻结?请查看我更新的问题。 我没有看到任何有问题的更新,只有格式编辑。无论如何,这只是一个巧合。你依赖了一些你真的不应该依赖的东西——所以结果是不可预测的——正如你已经注意到的那样。 所以我应该每 100 万次杀死和重生线程吗?还是我应该放弃 SDL 并转向 openGL? OpenGL 也不允许在同一个上下文中使用多线程,参见例如***.com/questions/11097170/… @askmish 你不应该从两个线程渲染到硬件表面。就这样。问题可能发生在任何一次通话中,而不是“偶尔”。 GL 也帮不了你。

以上是关于树莓派上 SDL 1.2 的奇怪线程死锁的主要内容,如果未能解决你的问题,请参考以下文章

使用Windbg分析多线程临界区死锁问题分享

多线程 死锁的模拟

线程同步——死锁问题

[linux] linux多线程详解

[linux] linux多线程详解

由 Dispatcher.Invoke 从多个线程调用的代码中的死锁