首页 > 解决方案 > 使用 importlib.import_module 避免分段错误的更安全方法

问题描述

import_module下面的语句失败后,当线程完成时,仅存在第二个线程就会导致分段错误。只有一个线程时没有段错误。

有没有更安全的方法来有条件地导入可能会根据系统环境出错的模块?也许是一种以某种方式“清除”C级错误或恢复到调用之前的状态的方法import_module

我不打算解决导致 Segfault 的问题。我有兴趣防止这使我的应用程序崩溃。

同样出于好奇,为什么只有在有第二个线程时才会发生这种情况?

# example of issue.
import sys
import time
import threading
import importlib

def main():
    try:
        cv2 = importlib.import_module('cv2')
    except Exception as e:
        print(str(e))

################################################################################
# Segmentation fault only occurs when a second thread is created.
# if this section is commented out no Segfault occurs
    def fn():
        for i in range(0, 3):
            time.sleep(1)
            print(str(i))

    t = threading.Thread(target=fn, daemon=True)
    t.start()

    print("waiting for thread.")
    t.join()
    print("Thread finished.") # <--- Never called. Segafaults before this.

################################################################################

    return 0

if __name__ == '__main__':
    sys.exit(main())

这是 gdb 回溯的输出。该问题是由于缺少cv2需要的共享库引起的

libcblas.so.3: cannot open shared object file: No such file or directory


Thread 2 "python3" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb666d460 (LWP 19304)]
0xb6fdab80 in elf_machine_rel (skip_ifunc=0, reloc_addr_arg=0xb2df4ff0, version=0x20, sym=0xb2de4170, reloc=0xb2de4340, map=0x4c3518)
    at ../sysdeps/arm/dl-machine.h:394
394     ../sysdeps/arm/dl-machine.h: No such file or directory.
(gdb) backtrace
#0  0xb6fdab80 in elf_machine_rel (skip_ifunc=0, reloc_addr_arg=0xb2df4ff0, version=0x20, sym=0xb2de4170, reloc=0xb2de4340, map=0x4c3518)
    at ../sysdeps/arm/dl-machine.h:394
#1  elf_dynamic_do_Rel (skip_ifunc=0, lazy=<optimized out>, nrelative=<optimized out>, relsize=<optimized out>, reladdr=<optimized out>, 
    map=0x4c3518) at do-rel.h:137
#2  _dl_relocate_object (scope=<optimized out>, reloc_mode=reloc_mode@entry=0, consider_profiling=<optimized out>) at dl-reloc.c:258
#3  0xb6fe2278 in dl_open_worker (a=0xb666cb60) at dl-open.c:377
#4  0xb6deb508 in __GI__dl_catch_exception (exception=0xb666cbd8, operate=0xb6e20000, args=0xb666cb54) at dl-error-skeleton.c:196
#5  0xb6fe1c04 in _dl_open (file=0xb6f4cfcc "libgcc_s.so.1", mode=-2147483646, caller_dlopen=0xb6f4aebc <pthread_cancel_init+52>, 
    nsid=nsid@entry=-2, argc=2, argv=0xbefff654, env=0xbefff660) at dl-open.c:599
#6  0xb6dea880 in do_dlopen (ptr=0xb666cdcc) at dl-libc.c:96
#7  0xb6deb508 in __GI__dl_catch_exception (exception=0x0, exception@entry=0xb666cd78, operate=0xb6e20000, args=0xb666cd78, 
    args@entry=0x152) at dl-error-skeleton.c:196
#8  0xb6deb5c8 in __GI__dl_catch_error (objname=0xb666cdac, objname@entry=0xb666cda4, errstring=0xb666cdb0, errstring@entry=0xb666cda8, 
    mallocedp=0xb666cdab, mallocedp@entry=0xb666cda3, operate=<optimized out>, args=0xb666cdcc, args@entry=0xb666cdc4)
    at dl-error-skeleton.c:215
#9  0xb6dea9cc in dlerror_run (operate=<optimized out>, args=args@entry=0xb666cdc4) at dl-libc.c:46
#10 0xb6deaa70 in __GI___libc_dlopen_mode (name=<optimized out>, mode=mode@entry=-2147483646) at dl-libc.c:195
#11 0xb6f4aebc in pthread_cancel_init () at ../sysdeps/nptl/unwind-forcedunwind.c:53
#12 0xb6f4b080 in _Unwind_ForcedUnwind (exc=0xb6f4b080 <_Unwind_ForcedUnwind+88>, stop=0x1, stop_argument=0xb666d6a8)
    at ../sysdeps/nptl/unwind-forcedunwind.c:127
#13 0xb6f48bb8 in __GI___pthread_unwind (buf=<optimized out>) at unwind.c:121
#14 0xb6f3f7f8 in __do_cancel () at pthreadP.h:304
#15 __pthread_exit (value=<optimized out>) at pthread_exit.c:28
#16 0x0022ecb4 in PyThread_exit_thread ()
#17 0x0020e868 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

注意:解决问题是只安装缺少的库

apt install libatlas3-base 但如前所述,如果出现此问题,我想防止应用程序崩溃。cv2如果没有成功导入,我的应用程序能够以减少的功能运行。

错误 20839opencv-python/issues/381听起来可能是相关的。

“在 dlopen 的实现中存在一些情况,其中调用 _dl_signal_error 而不删除所有部分初始化的链接映射。下游错误报告是指从 _dl_map_object 引发的错误,以响应丢失的文件(对 _dl_signal_error 的最终调用)。我们这样做进行了一些清理,但似乎我们跳过了 NODELETE 对象的删除。”

更新

libcblas.so.3通过使用 pip: 安装不同版本的 opencv, 即使系统上缺少 Segfault,我也能够防止 Segfault opencv-python-headless 。似乎与opencv-pythonand可能存在一些冲突PyQt5。这并不能回答我的问题,但可以让我继续前进。如果有人有答案,我仍然对原始问题的答案感兴趣。

标签: pythonmultithreadingopencv

解决方案


推荐阅读