By default, when compiling with /clr (not /clr:pure), the definition of a managed function causes the compiler to generate a managed entry point and a native
entry point. This allows the managed function to be called from native and managed call sites. However, when a native entry point exists, it can be the entry
point for all calls to the function. If a calling function is managed, the native entry point will then call the managed entry point. In effect, two calls
are required to invoke the function (hence, double thunking). For example, virtual functions are always called through a native entry point.
One resolution is to tell the compiler not to generate a native entry point for a managed function, that the function will only be called from a managed
context, by using the __clrcall calling convention.
Similarly, if you export (dllexport, dllimport) a managed function, a native entry point is generated and any function that imports and calls that function
will call through the native entry point. To avoid double thunking in this situation, do not use native export/import semantics; simply reference the
metadata via #using (see The #using Directive).
In Visual C++ 2005 the compiler was updated to reduce unnecessary double thunking. For example, any function with a managed type in the signature (including
return type) will implicitly be marked as __clrcall. For more information on double thunk elimination, see
http://msdn.microsoft.com/msdnmag/issues/05/01/COptimizations/default.aspx.
Example
The following sample demonstrates double thunking. When compiled native (without /clr), the call to the virtual function in main generates one call to T's
copy constructor and one call to the destructor. Similar behavior is achieved when the virtual function is declared with /clr and __clrcall. However, when
just compiled with /clr, the function call generates a call to the copy constructor but there is another call to the copy constructor due to the
native-to-managed thunk.
純 MSIL 程序集可以調用非托管函數,但不能由非托管函數調用。因此,與非托管函數使用的服務器代碼相比,純 MSIL 更適合于使用非托管函數的客戶端代碼。
當我們使用/clr選項(不是/clr:pure)進行編譯的時候,一個托管函數(managed function),會導致編譯器生成一個托管的入口點(managed entry point)和一個原生的入口點
(native entry point),這樣可以使得托管函數既可以被托管代碼調用,也可以被原生代碼調用。但是,當一個原生的入口點存在的時候,它將成為所有調用的入口點。也就是說
如果調用者是托管的,它還是會先去調用原生入口點,然后原生的入口點再去調用托管的入口點,這就意味著調用了兩次函數入口點(Double Thunking)。
c++ cli 標準