CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT
CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT 是在 .NET Framework 版本 2.0 中引入的。 .NET Framework 4 版 在两个方案中返回此 HRESULT:
任何时间劫持探查器强行重置线程的时注册上下文,使得线程尝试访问不一致状态的结构时。
当探查器尝试调用信息方法,该信息方法从禁止垃圾收集的回调方法出发垃圾收集时。
以下几节对这两种情况进行了探讨。
拦截探查器
(这种情况主要是拦截探查器的问题,尽管存在未拦截探查器可以查看此 HRESULT 的情况。)
在此情形中,劫持探查器强行将线程的寄存器上下文重置为任意时间,以便线程可以通过 ICorProfilerInfo 方法输入探查器代码或重新输入公共语言运行时 (CLR)。
许多分析 API 的 ID 都指向 CLR 中的数据结构。 许多 ICorProfilerInfo 调用只是读取这些数据结构的信息,并将它们传回。 但是,CLR 可能会在运行时更改这些结构中的内容,并且可能会使用锁来完成此操作。 假设 CLR 在探查器劫持线程时已持有(或尝试获取) 锁。 如果线程重新输入 CLR 并尝试采用更多的锁或检查正被修改的结构,这些结构可能处于不一致的状态。 在此类情况下很容易发生死锁和访问冲突。
一般情况下,当非劫持探查器执行 ICorProfilerCallback 方法内的代码并使用有效参数调用到 ICorProfilerInfo 方法时,不应死锁或收到访问冲突。 例如,在 ICorProfilerCallback::ClassLoadFinished 方法内运行的探查器代码会通过调用 ICorProfilerInfo2::GetClassIDInfo2 方法询问有关类的信息。 该代码可能会接收到表明信息不可用的 CORPROF_E_DATAINCOMPLETE HRESULT;但是,它不会死锁或接收到访问冲突。 此类对于 ICorProfilerInfo 的调用称为同步,因为它们源自 ICorProfilerCallback 方法。
但是,执行不在 ICorProfilerCallback 方法内的代码的托管线程被视为进行异步调用。 在 .NET Framework 版本 1 中,很难确定异步调用中可能发生的情况。 调用可能死锁、崩溃,或给出无效的回答。 .NET Framework 版本 2.0 引入了一些简单的检查,以帮助您避免此问题。 在 .NET Framework 2.0 中,如果异步调用不安全的 ICorProfilerInfo 函数,它将因 CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT 而失败。
一般情况下,异步调用是不安全的。 但是,以下方法都是安全的,并且专门支持异步调用:
有关其他信息,请参见 CLR 分析 API 博客中的条目 Why we have CORPROF_E_UNSUPPORTED_CALL_SEQUENCE。
触发垃圾回收
此方案中涉及在回调方法(例如 ICorProfilerCallback 方法之一)中运行的探查器,该方法禁止垃圾收集。 如果探查器尝试调用可能触发垃圾回收的信息性方法(例如:ICorProfilerInfo 接口上的方法),该信息性方法将会因 CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT 而失败。
下表显示了禁止垃圾回收的回调方法以及可能会触发垃圾回收的信息性方法。 如果探查器在某个列出的回调方法内执行,并调用某个列出的信息性方法,该信息性方法将会因 CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT 而失败。
禁止垃圾回收的回调方法 |
触发垃圾回收的信息性方法 |
---|---|