Aracılığıyla paylaş


Çift Dönüştürme (C++)

Çift çalıştırma, yönetilen bağlamdaki bir işlev çağrısı Visual C++ yönetilen işlevini çağırdığında ve program yürütmenin yönetilen işlevi çağırmak için işlevin yerel giriş noktasını çağırdığında karşılaşabileceğiniz performans kaybını ifade eder. Bu konu, çift pernkingin nerede gerçekleştiğini ve performansı geliştirmek için bundan nasıl kaçınabileceğinizi açıklar.

Açıklamalar

Varsayılan olarak, /clr ile derlenirken yönetilen işlevin tanımı derleyicinin yönetilen bir giriş noktası ve yerel giriş noktası oluşturmasına neden olur. Bu, yönetilen işlevin yerel ve yönetilen çağrı sitelerinden çağrılmasını sağlar. Ancak, yerel bir giriş noktası mevcut olduğunda, işleve yapılan tüm çağrılar için giriş noktası olabilir. Bir çağrı işlevi yönetiliyorsa, yerel giriş noktası yönetilen giriş noktasını çağırır. Aslında, işlevi çağırmak için iki çağrı gerekir (bu nedenle, çift thunking). Örneğin, sanal işlevler her zaman yerel bir giriş noktası aracılığıyla çağrılır.

Çözümlerden biri, derleyiciye yönetilen bir işlev için yerel giriş noktası oluşturmaması gerektiğini, işlevin yalnızca __clrcall çağırma kuralı kullanılarak yönetilen bağlamdan çağrılacağını söylemektir.

Benzer şekilde, yönetilen bir işlevi dışarı aktarırsanız (dllexport, dllimport) yerel bir giriş noktası oluşturulur ve bu işlevi içeri aktaran ve çağıran herhangi bir işlev yerel giriş noktası üzerinden çağrılır. Bu durumda iki kez thunking önlemek için yerel dışarı/içeri aktarma semantiği kullanmayın; #using (bkz . #using Yönergesi).

Derleyici gereksiz çift pernking'i azaltacak şekilde güncelleştirildi. Örneğin, imzada yönetilen türe sahip tüm işlevler (dönüş türü dahil) örtük olarak olarak __clrcallişaretlenir.

Örnek: Çift thunking

Tanım

Aşağıdaki örnekte çift thunking gösterilmektedir. Yerel olarak derlendiğinde (/clr olmadan), içindeki main sanal işleve yapılan çağrı, 'nin kopya oluşturucusunun Tbir çağrısını ve yıkıcıya yapılan bir çağrıyı oluşturur. Sanal işlev /clr ve __clrcallile bildirildiğinde benzer davranış elde edilir. Ancak, yalnızca /clr ile derlendiğinde, işlev çağrısı kopya oluşturucuya bir çağrı oluşturur, ancak yerelden yönetilen thunk nedeniyle kopya oluşturucusunun başka bir çağrısı vardır.

Kod

// double_thunking.cpp
// compile with: /clr
#include <stdio.h>
struct T {
   T() {
      puts(__FUNCSIG__);
   }

   T(const T&) {
      puts(__FUNCSIG__);
   }

   ~T() {
      puts(__FUNCSIG__);
   }

   T& operator=(const T&) {
      puts(__FUNCSIG__);
      return *this;
   }
};

struct S {
   virtual void /* __clrcall */ f(T t) {};
} s;

int main() {
   S* pS = &s;
   T t;

   printf("calling struct S\n");
   pS->f(t);
   printf("after calling struct S\n");
}

Örnek Çıkış

__thiscall T::T(void)
calling struct S
__thiscall T::T(const struct T &)
__thiscall T::T(const struct T &)
__thiscall T::~T(void)
__thiscall T::~T(void)
after calling struct S
__thiscall T::~T(void)

Örnek: Çift thunking etkisi

Tanım

Önceki örnekte çift thunking varlığı gösterilmiştir. Bu örnek etkisini gösterir. Döngü for sanal işlevi çağırır ve program yürütme süresini raporlar. Program /clr ile derlendiğinde en yavaş süre bildirilir. /clr olmadan derleme yapılırken veya sanal işlev ile __clrcallbildirilirken en hızlı süreler bildirilir.

Kod

// double_thunking_2.cpp
// compile with: /clr
#include <time.h>
#include <stdio.h>

#pragma unmanaged
struct T {
   T() {}
   T(const T&) {}
   ~T() {}
   T& operator=(const T&) { return *this; }
};

struct S {
   virtual void /* __clrcall */ f(T t) {};
} s;

int main() {
   S* pS = &s;
   T t;
   clock_t start, finish;
   double  duration;
   start = clock();

   for ( int i = 0 ; i < 1000000 ; i++ )
      pS->f(t);

   finish = clock();
   duration = (double)(finish - start) / (CLOCKS_PER_SEC);
   printf( "%2.1f seconds\n", duration );
   printf("after calling struct S\n");
}

Örnek Çıkış

4.2 seconds
after calling struct S

Ayrıca bkz.

Karışık (Yerel ve Yönetilen) Derlemeler