如何终止通过Python ctypes.LoadLibrary加载C库创建的pthreads线程
未存储ID的C库串口线程终止及资源释放方案
方案1:修改C库新增退出接口(最稳定,无兼容性问题)
- 在C库中新增
volatile int serial_exit_flag = 0全局变量,将原有线程的while(1)循环条件替换为while(!serial_exit_flag) - 导出
void stop_serial_workers()接口,接口内部将serial_exit_flag置1,同时主动调用close()关闭已打开的串口文件描述符 - Python层在需要释放串口时,先通过ctypes调用该
stop_serial_workers接口,等待100~200ms确认线程完全退出后,即可操作串口或执行模块重载
方案2:直接调用pthread接口终止线程(无C库修改权限时使用,仅支持Linux)
- 首先通过ctypes导入libpthread的
pthread_cancel、pthread_join接口 - 遍历
/proc/self/task目录获取当前进程所有线程ID,过滤掉Python主线程ID(可通过threading.get_ident()获取) - 对剩余线程逐个调用
pthread_cancel(tid)发送终止信号,再调用pthread_join(tid, NULL)回收线程资源,完成后串口会被系统自动释放
示例代码:
import ctypes import threading import os # 加载pthread库 libpthread = ctypes.CDLL("libpthread.so.0") pthread_cancel = libpthread.pthread_cancel pthread_cancel.argtypes = [ctypes.c_ulong] pthread_join = libpthread.pthread_join pthread_join.argtypes = [ctypes.c_ulong, ctypes.POINTER(ctypes.c_void_p)] main_tid = threading.get_ident() # 遍历当前进程所有线程 for tid_str in os.listdir("/proc/self/task"): tid = int(tid_str) if tid == main_tid: continue # 终止并回收非主线程 pthread_cancel(tid) pthread_join(tid, None)
方案3:卸载动态库强制释放资源(适配重载场景)
- 保存
ctypes.LoadLibrary返回的动态库句柄,需要释放资源时调用libdl的dlclose()接口卸载整个动态库:ctypes.CDLL("libdl.so").dlclose(lib_handle) - 卸载操作会释放动态库持有的所有系统资源,包括打开的串口句柄、线程占用的内存,大部分场景下会自动终止库创建的后台线程
- 卸载完成后直接调用
importlib.reload重新加载模块,即可恢复原有功能
注意:所有方案执行完成后,都建议调用串口打开接口测试一次,确认无占用后再执行后续业务逻辑,避免残留资源导致报错。
内容的提问来源于stack exchange,提问作者Hubert Bossy
相关产品推荐
相关产品推荐

