Debugging Bug Check 0x9F: DRIVER_POWER_STATE_FAILURE

本文深入探讨了Windows系统中电源状态转换时可能出现的问题,特别是当设备驱动未能在规定时间内响应电源请求导致的系统崩溃。文章详细分析了DRIVER_POWER_STATE_FAILURE错误的触发条件,解释了系统如何通过定时器监控电源请求的处理,并提供了调试步骤和实例,帮助开发者定位并解决此类问题。

In Windows Vista and later version of Windows, when the system changes power states i.e. transitions from a working state (S0) to a lower power state like standby (S3), hibernate (S4) or shutdown (S5) or vice versa, every driver in the system is notified about the transition via a system power IRP (S-IRP). In response to these system power state change requests, drivers power down their devices by requesting device power IRPs (D-IRP) and then sending them down to the underlying bus driver. For every power IRP that is sent to a driver, the power manager starts a watchdog timer that fires if the IRP is not completed within 10 minutes. The resultant timer DPC routine that runs at the end of this period crashes the system with the following bug-check code and parameters as displayed by the kernel debugger command "!analyze -v".

DRIVER_POWER_STATE_FAILURE (9f)
A driver is causing an inconsistent power state.
Arguments:
Arg1: 00000003, A device object has been blocking an Irp for too long a time
Arg2: 86b3e6e8, Physical Device Object of the stack
Arg3: 82d3fae0, Functional Device Object of the stack
Arg4: 852bc6f0, The blocked IRP

In the above output the description displayed for Arg1 alludes to the situation that led to the crash. The kernel debugger command "!poaction" displays information about the power state transition in progress. The output shown below indicates that system is going to sleep i.e. S3 power state.

0: kd> !poaction
PopAction: 82d50a60
  State..........: 3 - Set System State
  Updates........: 0 
  Action.........: Sleep
  Lightest State.: Sleeping3
  Flags..........: 80000004 OverrideApps|Critical
  Irp minor......: SetPower
  System State...: Sleeping3
  Hiber Context..: 00000000

Power Watchdog Timer

Although the crashing thread stack below shows the sequence of calls that led to the call to KeBugCheckEx(), it fails to identify the component that is responsible for the crash. Finding that culprit will require some more work beyond just running "!analyze -v"

nt!KeBugCheckEx
nt!PopCheckIrpWatchdog
nt!PopCheckForIdleness
nt!KiProcessTimerDpcTable
nt!KiProcessExpiredTimerList
nt!KiTimerExpiration
nt!KiRetireDpcList
nt!KiIdleLoop

The above sequence of calls is trigged by timer expiration as identified by the presence of KiProcessExpiredTimerList(). The kernel debugger command "!timer" lists all the pending timers in the system, one of which is the timer that has the DPC routine PopCheckForIdleness() associated with it, as shown below :

kd> !timer
.
.
.
83154a40 P 4f9aa283 00000014 [ 2/18/2011 13:47:08.239]  nt!PopCheckForIdleness (DPC @ 83154a20)

The DPC routine PopCheckForIdleness() fires periodically at an interval of 100 sec. It calls PopCheckIrpWatchdog() to scan the list of IRPs at nt!PopIrpList and increments a watchdog counter. Every time the DPC runs, it displays a debug message in the kernel debugger similar to the one below to warn about the impending bug-check:

Power Irp Watchdog: warning for PDO=86b3e6e8 Current=82d3fae0 IRP=852bc6f0 (2) status c00000bb
Power system watchdog warning (2 ticks)

When the count of timer expirations exceed the threshold stored in PopWatchdogMaxTicks (shown below), PopCheckIrpWatchdog() calls KeBugCheckEx(). So effectively, if a power IRP is not completed within 10 minutes from the time the IRP was sent to a driver, the system will bug-check with DRIVER_POWER_STATE_FAILURE.

0: kd> ? poi(nt!PopWatchdogMaxTicks)
Evaluate expression: 41 = 00000029

The kernel debugger output below displays details about the stuck power IRP that is responsible for the crash. Note that the pointer to this IRP is in Arg4 of the bug-check parameters.

0: kd> !irp 852bc6f0
Irp is active with 4 stacks 3 is current (= 0x852bc7a8)
 No Mdl: No System Buffer: Thread 00000000:  Irp stack trace.  
     cmd  flg cl Device   File     Completion-Context
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
>[ 16, 2]   0 e1 86359028 00000000 82f39f58-866040b0 Success Error Cancel pending
	       \Driver\vwifimp	nt!PopSystemIrpCompletion
			Args: 00014400 00000000 00000004 00000002
 [  0, 0]   0  0 00000000 00000000 00000000-866040b0    

			Args: 00000000 00000000 00000000 00000000

Component Identification

The device objects identified by the bug-check parameters Arg2 (Physical Device Object of the stack) and Arg3 (Functional Device Object of the stack), typically point to the lowest level device objects in the device stack. These device objects are owned by the bus and function drivers, respectively, in the device stack. This can be seen in the output of the kernel debugger command "!devstack" executed on the device object in Arg2 of the bug-check parameters.

0: kd> !devstack 86b3e6e8
  !DevObj   !DrvObj            !DevExt   ObjectName
  86359028  \Driver\vwifimp    863590e0  NDMP19
> 86b3e6e8  \Driver\vwifibus   86b3eff0  00000088
!DevNode 863996a0 :
  DeviceInst is "{5d624f94-8850-40c3-a3fa-a4fd2080baf3}\vwifimp\5&e3fd124&0&01"
  ServiceName is "vwifimp"

Although the bug-check parameters seem to imply that the bus and the function drivers are the culprits, more often than not their involvement in the crash is limited to the fact that they are the only drivers in the stack that actually process power IRPs and hence get blamed for any power IRP related crashes.

As an example, consider the networking sub-system in Windows - the components that drive the Network Interface Card (NIC) is the NDIS Miniport driver and the NDIS library (NDIS.sys). Since these two drivers are the power policy owners of the network stack, they are responsible for handing all of the S-IRPs and D-IRPs dispatched by the Power Manager. However, the drivers that are actually in the network data path i.e. the ones that process the networks data packets, comprise of NDIS Lightweight Filter Drivers, NDIS Intermediate Drivers, NDIS Protocol Drivers, TDI Filter Drivers, TDI Clients, WFP Filters, WSK Clients as well as the kernel mode socket driver (AFD.sys).

If any of these drivers block a network data packet for any reason, the adapter unbinding process that occurs when the system transitions from S0 to SX power state will not be able to complete. This in turn would result in power IRPs getting blocked at the miniport/NDIS level.

A key step in tracking down the root cause of power watchdog related bug-checks is to identify threads that are blocked on synchronization objects (i.e. events, semaphores, mutexes, push locks etc.) and would be signaled either when an outstanding operation completes or when the reference count on some data structure drops down to zero. These threads could be blocked in the hardware driver (function driver) or in higher level drivers that send requests to drivers below.

In order to identify threads that meet the above criteria, it is necessary to manually examine the kernel mode call stacks of all threads in the system, especially the threads in the system process that dispatch power requests. The kernel debugger commands "!stacks 2" and "!process 0 7" display the information required to identify such stacks.

The following example shows a thread stuck in the network stack. In this specific case, the NDIS function ndisUnbindProtocol() is requesting the NDIS intermediate driver (imdriver.sys) to tear down its binding to the underlying adapter. The NDIS intermediate driver's protocol unbind adapter entry point (i.e. ProtocolUnbindAdapter()) seems to be blocked on an event.

0: kd> !stacks 2
Proc.Thread  .Thread  Ticks   ThreadState Blocker
                            [84c3aab8 System]
.
.
.
   4.000014  84ca7850 0009811 Blocked   nt!KiSwapContext+0x26
                                        nt!KiSwapThread+0x266
                                        nt!KiCommitThreadWait+0x1df
                                        nt!KeWaitForSingleObject+0x393
                                        ndis!NdisWaitEvent+0x55
                                        imdriver+0x98ddc
                                        ndis!ndisUnbindPrototol+0x251
                                        ndis!ndisPnPNotifyAllTransports+0x1f6
                                        ndis!ndisSetPower+0x9aa
                                        ndis!ndisPowerDispatch+0x1ce
                                        nt!PopIrpWorker+0x351
                                        nt!PspSystemThreadStartup+0x9e
                                        nt!KiThreadStartup+0x19

To ascertain that the right thread has been identified, the thread's wait time can be observed, keeping in mind that the power IRP watchdog would allow the IRP about 10 minutes to complete from the time of dispatch, so such threads should be blocked for at least 10 minutes.

0: kd> !thread 84ca7850
THREAD 84ca7850  Cid 0004.0014  Teb: 00000000 Win32Thread: 00000000 WAIT: (Executive) KernelMode Non-Alertable
    863ad89c  NotificationEvent
Not impersonating
DeviceMap                 89a08ae0
Owning Process            84c3aab8       Image:         System
Attached Process          N/A            Image:         N/A
Wait Start TickCount      71276          Ticks: 38929 (0:00:10:07.296)
Context Switch Count      148            IdealProcessor: 0             
UserTime                  00:00:00.000
KernelTime                00:00:00.000
Win32 Start Address nt!PopIrpWorker (0x82c244f2)
Stack Init 807c1fd0 Current 807c19c8 Base 807c2000 Limit 807bf000 Call 0
Priority 13 BasePriority 13 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5

The above thread prevents NDIS from tearing down binding for one of the NICs in the system causing it to block the power IRP completion. This, in turn, causes the power watch dog timer to bug-check the system. In this particular case, the NIC in question is a Virtual WiFi adapter driven by vwifimp.sys.

Further investigation is required to understand the set of conditions under which imdriver.sys is blocking the unbind operation. This typically requires access to the private symbols and source code of the driver in question as well as a good understanding of the driver's architecture.

Sample Stack Traces

The stack depicted above is, by no means, the only stack signature that could lead to blocked power IRPs. There could be a myriad of such conditions involving pretty much any driver in the system. This section lists similar thread stacks from systems that have bug-checked due to power IRP watchdog timeouts. Although most of the examples shown below are from the networking subsystem on Windows, similar issues can occur in any subsystem in the kernel.

NDIS miniport driver (driver.sys) blocking on a synchronization object in the MiniportHaltAdapter() callback.

nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
nt!KiSwapThread+0x266
nt!KiCommitThreadWait+0x1df
nt!KeWaitForSingleObject+0x393
driver+0xf0a9
driver+0x120dc
driver+0xb096
ndis!ndisMCommonHaltMiniport+0x54f (FPO: [Non-Fpo])
ndis!ndisPmHaltMiniport+0xfc (FPO: [Non-Fpo])
ndis!ndisSetPower+0x63a (FPO: [Non-Fpo])
ndis!ndisPowerDispatch+0x1ce (FPO: [Non-Fpo])
nt!PopIrpWorker+0x351
nt!PspSystemThreadStartup+0x9e
nt!KiThreadStartup+0x19

NDIS protocol driver (tcpip.sys) waiting for the reference count in a Rundown Protection Lock to drop to zero. Kernel mode components use Rundown Protection Locks to ensure that data structures protected by the lock are kept around for as long as there are references on the structure implying that the structure is in use by one or more threads in system.

nt!KiSwapContext
nt!KiSwapThread
nt!KiCommitThreadWait
nt!KeWaitForSingleObject
nt!ExWaitForRundownProtectionReleaseCacheAware
tcpip!FlUnbindAdapter
ndis!ndisUnbindProtocol
ndis!ndisCloseMiniportBindings
ndis!ndisPnPRemoveDevice
ndis!NdisIMDeInitializeDeviceInstance
driver!XxUnbindAdapter
ndis!ndisUnbindProtocol
ndis!ndisPnPNotifyAllTransports
ndis!ndisSetPower
ndis!ndisPowerDispatch
nt!PopIrpWorker
nt!PspSystemThreadStartup
nt!KiThreadStartup

NDIS waiting for a light weight filter driver to unbind from an underlying adapter.

nt!KiSwapContext
nt!KiSwapThread
nt!KeWaitForSingleObject
ndisPnPNotifyBinding
ndis!ndisPnPNotifyAllTransports
ndis!NdisFNetPnPEvent
ndis!ndisDevicePnPEventNotifyFiltersAndAllTransports
ndis!ndisQueryPower
ndis!ndisPowerDispatch
nt!PopIrpWorker
nt!PspSystemThreadStartup
nt!KiStartSystemThread

TDX.sys (TDI Compatibility Driver) waiting for a reference count on the "Transport Address" to drop to zero. The call to tdx!TdxDeactivateTransportAddress() is preventing power IRPs from being completed in the network stack.

nt!KiSwapContext
nt!KiSwapThread
nt!KeWaitForSingleObject
tdx!TdxDeactivateTransportAddress
tdx!TdxDeleteTransportAddress
tdx!TdxTdiDispatchCleanup
nt!IopCloseFile
nt!ObpDecrementHandleCount
nt!ObpCloseHandleTableEntry
nt!ObpCloseHandle
nt!KiSystemServiceCopyEnd
nt!KiServiceLinkage
netbt!DelayedNbtCloseFileHandles
netbt!CloseAddressesWithTransport
netbt!NbtSetNewAddress
netbt!TdiAddressNotification
TDI!TdiNotifyPnpClientList
TDI!TdiExecuteRequest
nt!ExpWorkerThread
nt!PspSystemThreadStartup
nt!KiStartSystemThread

AFD.sys (Windows Kernel Socket Driver) waiting for a file handle to be closed. The call to IopCloseFile() blocks, causing the power IRPs to be blocked in the network stack.

nt!KiSwapContext+0x26
nt!KiSwapThread+0x44f
nt!KeWaitForSingleObject+0x492
nt!IopCloseFile+0x39f
nt!ObpDecrementHandleCount+0x146
nt!ObpCloseHandleTableEntry+0x234
nt!ObpCloseHandle+0x73
nt!NtClose+0x20
nt!KiFastCallEntry+0x12a
nt!ZwClose+0x11
afd!AfdFreeConnectionResources+0x33
afd!AfdFreeConnectionEx+0xbf
afd!AfdFreeConnection+0x1d
afd!AfdDoWork+0x51
nt!IopProcessWorkItem+0x23
nt!ExpWorkerThread+0xfd
nt!PspSystemThreadStartup+0x9d
nt!KiThreadStartup+0x16

Upon further analysis, most of the issues depicted in the above call stacks were tracked down to the fact that one more Net Buffer Lists (NBLs) were stuck in some queue causing the driver that owns the queue to wait indefinitely for the NBLs to complete. The kernel debugger command "!ndiskd.pendingnbls" can prove to be useful in locating such pending/leaked NBLs. This command only works on Win7/Win2008R2 and later versions of Windows.

Lastly, the variables and function names referred to above have changed in Windows 8 and Windows Server 2012.

ubuntu@ubuntu-virtual-machine:~/GrabDetect/build$ gdb ./GrabDetect GNU gdb (Ubuntu 10.2-0ubuntu1~18.04~2) 10.2 Copyright (C) 2021 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./GrabDetect... (No debugging symbols found in ./GrabDetect) (gdb) run Starting program: /home/ubuntu/GrabDetect/build/GrabDetect [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Step into main CUDA可用: 否 未找到CUDA设备,使用CPU模式 OpenCV未启用CUDA支持(可能编译时未开启WITH_CUDA) 配置文件里的模型路径 = [grab.onnx] 配置参数 - SizeImage: 640, Confidence: 0.25, NMS: 0.25 模型路径: [grab.onnx] 使用CPU后端进行推理 files ./data//111.pcap Pcap = ./data//111.pcap [New Thread 0x7fffdf322700 (LWP 3566)] ============= step into ReadPacp ============= [New Thread 0x7fffdeb21700 (LWP 3567)] [New Thread 0x7fffde320700 (LWP 3568)] [New Thread 0x7fffddb1f700 (LWP 3569)] RealtimeThread 开始执行 [New Thread 0x7fffe32e2700 (LWP 3570)] [New Thread 0x7fffdd31e700 (LWP 3571)] [New Thread 0x7fffdcb1d700 (LWP 3572)] [New Thread 0x7fffdc31c700 (LWP 3573)] Thread 5 "GrabDetect" received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7fffddb1f700 (LWP 3569)] 0x0000000000000003 in ?? () (gdb) where #0 0x0000000000000003 in ?? () #1 0x00007ffff76c6233 in cv::dnn::dnn4_v20231225::Net::Impl::clear() () from /usr/local/lib/libopencv_dnn.so.409 #2 0x00007ffff76dd3c9 in cv::dnn::dnn4_v20231225::Net::Impl::setUpNet(std::vector<cv::dnn::dnn4_v20231225::detail::LayerPin, std::allocator<cv::dnn::dnn4_v20231225::detail::LayerPin> > const&) () from /usr/local/lib/libopencv_dnn.so.409 #3 0x00007ffff76de886 in cv::dnn::dnn4_v20231225::Net::Impl::forward(cv::_OutputArray const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) () from /usr/local/lib/libopencv_dnn.so.409 #4 0x00007ffff76be689 in cv::dnn::dnn4_v20231225::Net::forward(cv::_OutputArray const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) () from /usr/local/lib/libopencv_dnn.so.409 #5 0x000055555556d636 in check_Point::detect(cv::Mat const&, cv::dnn::dnn4_v20231225::Net&) () #6 0x000055555556bc46 in check_Point::point_dectect(pcl::PointCloud<pcl::PointXYZRGB> const&, check_Point::Three_Views_Group) () #7 0x000055555556e4ea in check_Grabs::find_Grabs(pcl::PointCloud<pcl::PointXYZRGB> const&, Vector3D const&) () #8 0x00005555555c83f7 in MainRealtime(std::vector<pcl::PointXYZRGB, std::allocator<pcl::PointXYZRGB> >, check_Grabs&) () #9 0x00005555555eb3bc in RealtimeThread(check_Grabs&) () #10 0x00005555555e4152 in void std::__invoke_impl<void, void (*)(check_Grabs&), std::reference_wrapper<check_Grabs> >(std::__invoke_other, void (*&&)(check_Grabs&), std::reference_wrapper<check_Grabs>&&) () #11 0x00005555555e406e in std::__invoke_result<void (*)(check_Grabs&), std::reference_wrapper<check_Grabs> >::type std::__invoke<void (*)(check_Grabs&), std::reference_wrapper<check_Grabs> >(void (*&&)(check_Grabs&), std::reference_wrapper<check_Grabs>&&) () #12 0x00005555555e3fb1 in void std::thread::_Invoker<std::tuple<void (*)(check_Grabs&), std::reference_wrapper<check_Grabs> > >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) () #13 0x00005555555e3f52 in std::thread::_Invoker<std::tuple<void (*)(check_Grabs&), std::reference_wrapper<check_Grabs> > >::operator()() () #14 0x00005555555e3f16 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(check_Grabs&), std::reference_wrapper<check_Grabs> > > >::_M_run() () #15 0x00007ffff137b67f in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #16 0x00007ffff37d96db in start_thread (arg=0x7fffddb1f700) at pthread_create.c:463 #17 0x00007ffff0a0a61f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
最新发布
11-06
从你的 GDB 调试信息来看,程序在运行时发生了 **段错误(Segmentation Fault)**,即访问了非法内存地址。我们来逐步分析问题,并给出解决方案。 --- ### 🔍 问题分析 #### 1. 关键错误信息: ```bash Thread 5 "GrabDetect" received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7fffddb1f700 (LWP 3569)] 0x0000000000000003 in ?? () ``` - `0x0000000000000003` 是一个极小的无效地址,说明你尝试调用了一个函数指针,但这个函数指针是 `NULL` 或未正确初始化。 - 这通常意味着:**某个对象没有正确构造或已被释放,却仍然被调用了方法。** #### 2. 回溯栈 (`where`) 分析: ```bash #0 0x0000000000000003 in ?? () #1 0x00007ffff76c6233 in cv::dnn::dnn4_v20231225::Net::Impl::clear() () from /usr/local/lib/libopencv_dnn.so.409 #2 0x00007ffff76dd3c9 in cv::dnn::dnn4_v20231225::Net::Impl::setUpNet(...) () #3 0x00007ffff76de886 in cv::dnn::dnn4_v20231225::Net::Impl::forward(...) () #4 0x00007ffff76be689 in cv::dnn::dnn4_v20231225::Net::forward(...) () #5 0x000055555556d636 in check_Point::detect(cv::Mat const&, cv::dnn::dnn4_v20231225::Net&) () ``` 关键点: - 程序崩溃在 `cv::dnn::Net::forward()` 的执行过程中。 - 实际上是在内部调用 `Impl::clear()` 时出错,而 `clear()` 是成员函数,说明 `this` 指针为 `nullptr`。 - 所以:**传入的 `cv::dnn::Net` 对象本身是不合法的!可能是未加载成功、局部变量被析构、或跨线程共享出错。** --- ### ✅ 根本原因推测 > **最可能的原因是:`cv::dnn::Net` 模型对象未成功加载,或者在线程间共享时出现问题。** 具体场景可能包括: 1. **模型文件 `grab.onnx` 不存在或路径错误** - 尽管打印了“模型路径: [grab.onnx]”,但如果文件读取失败,`readNetFromONNX()` 返回的是空对象。 2. **使用了已销毁的 `Net` 对象** - 如果 `Net` 是局部变量,在子线程中异步使用会导致悬垂引用。 3. **多线程并发访问同一 `Net` 实例** - OpenCV 的 `cv::dnn::Net` **不是线程安全的**,多个线程同时调用 `.forward()` 会引发未定义行为。 结合日志中的线程创建和调用栈: ```bash RealtimeThread 开始执行 [New Thread ...] ... Thread 5 "GrabDetect" received signal SIGSEGV ``` → 表明是在子线程中执行推理时崩溃,进一步支持“共享 Net 导致冲突”或“Net 未正确传递”。 --- ### 🛠️ 解决方案与代码建议 #### ✅ 步骤一:确保模型加载成功 在加载 ONNX 模型后必须检查是否为空! ```cpp #include <opencv2/dnn.hpp> cv::dnn::Net net = cv::dnn::readNetFromONNX("grab.onnx"); if (net.empty()) { std::cerr << "❌ 加载 ONNX 模型失败!请确认 grab.onnx 存在于当前目录。" << std::endl; return -1; } ``` > ⚠️ 注意:即使文件存在,若格式不兼容(如 OPSET 版本过高),也可能返回空。 #### ✅ 步骤二:避免多线程共用同一个 `Net` OpenCV DNN 不支持多线程并发推理。你需要: ##### 方案 A:使用锁保护(适用于低频推理) ```cpp std::mutex dnn_mutex; void check_Point::detect(const cv::Mat& image, cv::dnn::Net& net) { std::lock_guard<std::mutex> lock(dnn_mutex); cv::Mat blob; cv::dnn::blobFromImage(image, blob, 1.0/255.0, cv::Size(640, 640), cv::Scalar(), true, false); net.setInput(blob); std::vector<cv::Mat> outputs; try { net.forward(outputs); // 安全调用 } catch (const cv::Exception& e) { std::cerr << "OpenCV Exception: " << e.what() << std::endl; } } ``` ##### 方案 B:每个线程独立拥有 Net 实例(推荐用于实时系统) ```cpp // 每个线程内加载自己的 Net(只加载一次) thread_local cv::dnn::Net tl_net = [](){ cv::dnn::Net n = cv::dnn::readNetFromONNX("grab.onnx"); if (n.empty()) { throw std::runtime_error("无法加载 ONNX 模型"); } n.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); n.setPreferableTarget(cv::dnn::DNN_TARGET_CPU); // 或 DNN_TARGET_CUDA return n; }(); void check_Point::detect(const cv::Mat& img, void*) { // 使用 thread_local 的 net cv::Mat blob; cv::dnn::blobFromImage(img, blob, 1.0/255.0, cv::Size(640,640), cv::Scalar(), true, false); tl_net.setInput(blob); std::vector<cv::Mat> outs; tl_net.forward(outs); // 处理输出... } ``` > ✅ 优点:无锁、高效、避免竞争条件 > ❗ 缺点:占用更多显存(如果使用 GPU) #### ✅ 步骤三:验证 ONNX 模型可用性 你可以单独写一个测试程序验证模型能否正常加载并推理: ```cpp #include <opencv2/opencv.hpp> #include <opencv2/dnn.hpp> #include <iostream> int main() { auto net = cv::dnn::readNetFromONNX("grab.onnx"); if (net.empty()) { std::cerr << "Failed to load model." << std::endl; return -1; } net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU); cv::Mat dummy = cv::Mat::zeros(640, 640, CV_8UC3); cv::Mat blob; cv::dnn::blobFromImage(dummy, blob, 1./255, cv::Size(640,640), cv::Scalar(), true, false); net.setInput(blob); try { auto out = net.forward(); std::cout << "✅ 推理成功!输出维度:" << out.size << std::endl; } catch (cv::Exception& e) { std::cerr << "❌ 推理失败:" << e.what() << std::endl; } return 0; } ``` --- ### 💡 其他建议 | 建议 | 说明 | |------|------| | 编译时添加调试符号 | 使用 `-g` 编译:`g++ -g -o GrabDetect ...`,这样 GDB 才能显示行号 | | 启用核心转储 | `ulimit -c unlimited` 可生成 core 文件供事后调试 | | 检查 `LD_LIBRARY_PATH` | 确保链接的是正确的 OpenCV 库版本(尤其是 `/usr/local/lib`) | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值