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 博客中我们引入 CORPROF_E_UNSUPPORTED_CALL_SEQUENCE 的原因的条目。
触发垃圾回收
此场景涉及在禁止垃圾回收的回叫方法(例如 ICorProfilerCallback
方法之一)中运行的探查器。 如果探查器尝试调用可能会触发垃圾回收的信息性方法(例如 ICorProfilerInfo
接口上的一个方法),此信息性方法会失败并出现 CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT。
下表显示了禁止垃圾回收的回叫方法以及可能触发垃圾回收的信息性方法。 如果探查器在其中一个列出的回叫方法中执行并调用其中一个列出的信息性方法,该信息性方法会失败并出现 CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT。