简体   繁体   English

Python 脚本在 SIGINT “终止调用时没有活动异常时”后挂起

[英]Python script hangs after SIGINT “terminate called without an active exception when”

I have a python app that collects data from a sensor.我有一个从传感器收集数据的 python 应用程序。 The driver for the sensor is closed source and I have written a wrapper around it to simplify its use.传感器的驱动程序是闭源的,我在它周围编写了一个包装器以简化它的使用。 The entire application runs on Linux.整个应用程序在 Linux 上运行。 The program has the following flow.该程序具有以下流程。

  1. Python call into driver setup. Python 调用驱动程序设置。 This starts one std::thread that I control which polls the sensor and places the resulting data into an std::queue.这会启动一个我控制的 std::thread,它会轮询传感器并将结果数据放入 std::queue。 It also calls the closed source driver startup code which appears to start a couple of threads.它还调用似乎启动几个线程的闭源驱动程序启动代码。
  2. Python main thread starts looping picking things off of the queue of data from the sensor via a call into the c++ driver (driver.getData). Python 主线程通过调用 c++ 驱动程序 (driver.getData) 开始循环从传感器的数据队列中提取内容。 Once it has the data it does some buffering and after a fixed number of samples are aggregated they are written to a file.一旦获得数据,它就会进行一些缓冲,并在聚合固定数量的样本后将它们写入文件。
  3. Eventually I want the program to stop so I hit ctrl+c to send the process SIGINT.最终我希望程序停止,所以我按 ctrl+c 来发送进程 SIGINT。 I have a handler registered via the python signal.signal function that catches the signal changes the value of a boolean and returns.我有一个通过 python signal.signal function 注册的处理程序,它捕获信号更改 boolean 的值并返回。 I know the handler executes because I have a print statement at the start of the handler.我知道处理程序会执行,因为我在处理程序的开头有一个打印语句。
  4. At this point I would expect the main python thread to stop looping over its while loop (since the condition it checks has now been set to False by the handler) and run my cleanup code.此时,我希望主 python 线程停止循环其 while 循环(因为它检查的条件现在已被处理程序设置为 False)并运行我的清理代码。

Step 4 only happens if the c++ thread is not running (never started or has been stopped).第 4 步仅在 c++ 线程未运行(从未启动或已停止)时发生。 If the thread is running and I'm pulling things off of the sensor data queue I get a "terminate called without an active exception" and my application hangs.如果线程正在运行并且我正在从传感器数据队列中拉出东西,我会得到一个“没有活动异常的终止调用”并且我的应用程序挂起。 Other questions that mention this message point to not joining threads before exiting as the cause of the message but my code never gets to my join statement in my shutdown code.提到此消息的其他问题指向在退出之前未加入线程作为消息的原因,但我的代码永远不会在我的关闭代码中到达我的加入语句。

If I had to guess, it seems like one of the driver threads or my c++ thread is exiting as soon as SIGINT is issued causing the main python thread to hang waiting for a last piece of data to be placed in the queue (right now I'm sampling the sensor at a very low rate).如果我不得不猜测,似乎一个驱动程序线程或我的 c++ 线程在发出 SIGINT 后立即退出,导致主 python 线程挂起等待最后一条数据放入队列(现在我我以非常低的速率对传感器进行采样)。 But I could be totally wrong about this.但我可能完全错了。

Is there a reason the SIGINT signal could be stopping one of the other threads? SIGINT 信号是否有可能停止其他线程之一? If that's the case is there any way I can prevent this?如果是这种情况,有什么办法可以防止这种情况发生吗?

Thanks!谢谢!

A rough outline of my code.我的代码的粗略轮廓。

the main python app主 python 应用程序

import driver # this wraps a bunch of ctypes calls

def sigint_handler(sig,frame):
    print('handling SIGINT signal')
    global isRun
    isRun = false

global isRun
isRun = True

signal.signal(SIGINT,sigint_handler)
driver.setupDriver()

while isRun:
  data = driver.getData() 
  logger.log(data)

print('cleaning up')
driver.stopDriver() #this should stop the c++ threads
logger.stop()

my driver interface layer c++我的驱动接口层c++


std::queue<data_t> sensorDataQ()
std::mutex dataq_mutex()
std::thread worker
bool isRun = True;

void workerWork()
{
   while(isRun)
   {
   auto data = getData_sensor_primary_driver();

   {
       std::lock_guard(dataq_mutex)
       sensorDataQ.push(data)
   }
   }

}

extern "C" data_t getData()
{
    while(sensorDataQ.empty())
   {
      std::this_thread::sleep_for(50) //sleep for 50 miliseconds until we get some data
   }
   {
       std::lock_guard(dataq_mutex)
       sensorDataQ.push(data)
   }


}

extern "C" startDriver()
{
    start_sensor_primary_driver() // this appears to start 4 threads according to GDB
    worker = std::thread(workerWork)
    worker.start()
}

extern "C" stopDriver()
{
    isRun = false;
    worker.join()
    cleanup_primary_driver()
}

After some more digging around looks like the base driver is registering a handler for the SIGINT signal and calling exit before I have a chance to cleanup my threads.经过更多的挖掘之后,看起来基本驱动程序正在为 SIGINT 信号注册一个处理程序并在我有机会清理我的线程之前调用 exit。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM