Makale numarası: 163449 - Son Gözden Geçirme: 21 Şubat 2007 Çarşamba - Gözden geçirme: 4.2

Bir genişletilmiş saklı yordamı iş parçacığı yerel depolama kullanımda

Sistem İpucuBu makale, kullandığınızdan farklı bir işletim sistemine yöneliktir. Sizinle ilgili olmayabilecek makale içeriği devre dışı bırakıldı.

Bu Sayfada

Hepsini aç | Hepsini kapa

Özet

Iş parçacığı yerel depolama (TLS), çok hassas bir konu olabilir. Ortam havuzu iş parçacığı içinde çalışırken, TLS ve iş parçacığı etkileşimleri sonuçları anlamak çok önemlidir.

Microsoft SQL Server gibi bir ortam havuzu bir iş parçacığında TLS önlemek önerilir. Ancak, TLS kullanmanız gerekiyorsa, lütfen dikkatle bu belgeyi okuyun ve TLS ve DLL ana işlevler için Win32 SDK'sındaki çevrimiçi belgelere bakın.

Ayrıca, genişletilmiş saklı yordamda derleyici yönergesini __declspec(thread) desteklenmiyor. LoadLibarary gerçekleştiğinde __declspec(thread) tanım düzgün başlatılamadı. Daha fazla bilgi için bkz: Jeffrey Ricter tarafından "Windows Gelişmiş".



Not: SQL Server'a genişletilmiş saklı yordamlar da dahil olmak üzere, herhangi bir uzantısı hiçbir zaman DisableThreadLibraryCalls() çağrı yapabilir.

Daha fazla bilgi

Belirtildiği gibi işlev çağrılarını TlsSetValue ve TlsGetValue kullanılan dizin değeri TlsAlloc işlevini verir. Belgelere DLLMain işlevinizin TlsAlloc işlev çağrısı önerir, ul_reason_for_call DLL_PROCESS_ATTACH =. Varsayılan olarak, başlangıçta yüklenen DLL'NIN DLL_PROCESS_ATTACH denir.

DLL_PROCESS_ATTACH ve DLL_THREAD_ATTACH, bellek ve TlsSetValue arayın. Bu, özellikle iş parçacığı havuzu senaryosunda bazı sorunlara neden başladığı olur.

Aşağıda, havuzu iş parçacığı herhangi bir uygulama için geçerli bir örnek senaryodur. Bu örnek Microsoft SQL sunucu uygulamasını kullanır.

Birkaç temellerini öğrenmeniz gerekir, örneğin şunlardır: Bu tüm altında DLLMain işlevi Win32 SDK belgelerinde ayrıntılı olarak belgelenmektedir.
  • Bir DLL yüklendiğinde, DLL_PROCESS_ATTACH çağırır.
  • (DLL yüklendikten sonra kökenli) tüm sonraki iş parçacığı DLL_THREAD_ATTACH arayın.
  • Şu anda çalışan iş parçacığı (DLL yüklenmeden önce kökenli) DLL_THREAD_ATTACH çağırmayın.
  • Tüm iş parçacıkları, bile, bunların hiçbir zaman DLL_THREAD_ATTACH adlı DLL_THREAD_DETACH, arayın.
Örneğin, aşağıdaki grafik sipariş ve SQL Server'ın işçi iş parçacığı havuzu kullanımını gösterir varsayalım:
   Thread     ATTACH CALLED     COMMAND     USER
------------------------------------------------ 
     1              NO           select      Joe
     2             YES          xp_test     Mary
     3             YES           select     Adam

     1              NO          xp_test     Lynn
				

Can, uzun süren bir seçme deyimini başlatır. Bu nedenle yolu olarak DLL_ATTACH işleminin hiç kimsenin genişletilmiş saklı yordamı henüz xp_test kullandı.

Gamze, Can'ın seçin çalışırken xp_test çalışır. Mekanizması havuzu iş parçacığı, yeni bir iş parçacığı isteğine hizmet Can'ın kökenli belirler. SQL Server, daha sonra Xproc.dll dosyasını yüklemek için LoadLibrary işlevini çağırır. Böylece, DLL_PROCESS_ATTACH olarak adlandırılır; bu nedenle, dll DOSYASıNıN eklemek için ilk iş parçacığının iş parçacığı 2 olur. Daha önce anlatıldığı gibi TlsAlloc genişletilmiş saklı yordamın TLS dizin değeri'ni başlatmak için çağrılabilir.

Gamze, Can'ın ve Can'ın komutlarını çalıştırırken, kendi seçme gönderir. Yeniden Gamze'nın bir isteği işlemek için yeni bir iş parçacığı kökenli. LoadLibrary yer aldığı sonra iş parçacığı 3 kökenli olduğundan, iş parçacığının 3 DLL_THREAD_ATTACH çağırır. Belirtildiği gibi 3 iş parçacığı için bellek ayrılamadı ve TlsSetValue call budur.

Can'ın seçin tamamlandığını varsayalım, şimdi, böylece işçi iş parçacığı 1 kullanımı için ücretsizdir. Lynn xp_test komutu gönderir ve iş parçacığı 1 atanır. Önceden 1 numaralı olan iş parçacığı, hiçbir zaman DLL_PROCESS_ATTACH veya DLL_THREAD_ATTACH çağırır, iş parçacığının önce kökenli çünkü LoadLibrary çağrıldı.

Bu örnekte, TlsGetValue ile TLS belleğe erişme girişimleri 1 iş parçacığı tarafından bir NULL işaretçisiyle verilen sonuçlar görebilirsiniz. Bu koşulu denetlemek için genişletilmiş saklı yordamın düzgün yazılmaz, NULL adresine yazmaya çalıştığınızda erişim ihlali oluşuyor (AV) karşılaşırsınız.

Aşağıda belirtilen iş parçacığı havuzu ve TLS hakkında gereken birkaç nokta şunlardır.

TLS havuz bir ortamda kullanıyorsanız, her zaman NULL bir dönüş değeri için TlsGetValue denetlemeniz gerekir. NULL geldiğinizde, bellek ve çağrı LoadLibrary yer aldığı için önce kökenli burada akıtır TlsSetValue olanlar işlemek için doğru tahsis gerekir.

Başka bir uyarı doğrudan belgelerinde açıklanan bile, iş parçacığının DLL dosyasında hiçbir zaman işlevlerini kullanır, DLLMain işlevi TLS bellekte sonra LoadLibarary, kökenli her iş parçacığı için tahsis, ' dir. Yukarıdaki örnekte, bu iş parçacığıyla 3 gösterir. Yalnızca bir seçin çalıştı, ancak, genişletilmiş saklı yordamı için TLS bellek tahsis DLL_THREAD_ATTACH adlı.

Bir ortam havuzu iş parçacığı bu tasarım koyarsanız, her zaman kullanılabilir bellek ayrılamadı.

Bellek ayırma en iyi duruma getirmek için en iyi yolu şudur:
  1. Doğru TLS dizin değerini, DLL_PROCESS_ATTACH içinde TlsAlloc edinin.
  2. DLL_PROCESS_ATTACH veya DLL_THREAD_ATTACH bellek ayrılamadı.
  3. TLS değerini almak için genel bir fonksiyonu tasarım; BOş ise, doğru olarak, ayırmak ve TlsSetValue arayın.

    Bu adım, bellek ayırma gerçekten kullanmak bu iş parçacığı kısıtlar. Bu alt iş parçacığı Genel giderleri ve başlangıç saatini önemli ölçüde azaltabilir. Ayrıca, doğru yerde LoadLibrary sürdü önce kökenli bu iş parçacığı işlemek için artıklık oluşturur.
  4. DLL_PROCESS_DETACH ve DLL_THREAD_DETACH her zaman olarak adlandırılır, çünkü bu işlemler belleği boşaltın.
Yine de belirsiz olabilir yalnızca şey TlsAlloc çağrısı ' dir. Belgeleri okuma, döndürülen TLS dizin değerini, genel bir değer olduğunu görünebilir. Genel bir değerdir, ancak her bir ça?r? TlaAlloc farklı bir dizin değeri verir. Bu, kendi TLS dizin değerine sahip ve diğerlerini etkilemeden kendi TLS verilerini düzgün bir şekilde işler iki genişletilmiş saklı yordamlar sağlar.

Aşağıdaki örnekte açıklanan davranış gösteren bir genişletilmiş saklı yordamdır:
   // 
   //    1. Start SQL Server from the command prompt to see the output:
   //       ...\Mssql\Binn\Sqlservr -c
   // 
   //    2. Run Xproctst.cmd to show the behavior.
   // 
   #include "windows.h"
   #include "stdio.h"
   #include "srv.h"
 
   #define           TLS_FAIL    0xFFFFFFFF

   DWORD          dwTlsIndex     =  TLS_FAIL;
   DWORD          dwCounter      =  0;
   CRITICAL_SECTION  csSync;

   // 
   //    Cleanup TLS memory
   // 
   void vCleanUpTls(void)
   {
      char *   strData     =  NULL;
      if(TLS_FAIL != dwTlsIndex)
      {
         strData = TlsGetValue(dwTlsIndex);
         if(NULL != strData)
         {
            free(strData);
            printf("\n >>> Tls memory released by thread %ld",
   GetCurrentThreadId());
         }
      }
   }
   // 
   //    Setup the TLS pointer
   // 
   void vSetUpTls(void)
   {
      char *      strData  =  NULL;
      if(TLS_FAIL == dwTlsIndex)
      {
         dwTlsIndex = TlsAlloc();
      }
      // 
      //    Are we ready to go
      // 
      if(TLS_FAIL != dwTlsIndex)
      {
         strData = (char *) calloc(256,1);
         if(strData)
         {
            printf("\n >>> Tls memory allocated by thread %ld",
   GetCurrentThreadId());
            if(TRUE == TlsSetValue(dwTlsIndex, strData))
            {
               // 
               //    Protect the counter.
               // 
               EnterCriticalSection(&csSync);
               sprintf(strData, "Counter = %ld", ++dwCounter);
               LeaveCriticalSection(&csSync);
            }
            else
            {
               printf("\n >>> *** Serious error *** TlsSetValue
               failed.\n");
            }
         }
         else
         {
            printf("\n >>> *** Serious error *** can not allocate
            memory.\n");
         }
      }
      else
      {
         printf("\n >>> *** Serious error *** TlsAlloc failed.\n");
      }
   }
   // 
   //    DLLMain
   // 
   BOOL APIENTRY DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID
   lpReserved)
   {
      char  strInfo[256]   =  "";
      switch(ul_reason_for_call)
      {
         case DLL_PROCESS_ATTACH:
            InitializeCriticalSection(&csSync);
            vSetUpTls();
            sprintf(strInfo, "\n >>> DLL_PROCESS_ATTACH Thread: %ld",
   GetCurrentThreadId());
            break;
        case DLL_THREAD_ATTACH:
            vSetUpTls();
            sprintf(strInfo, "\n >>> DLL_THREAD_ATTACH Thread: %ld",
   GetCurrentThreadId());
            break;
         case DLL_PROCESS_DETACH:
            vCleanUpTls();
            if(TLS_FAIL != dwTlsIndex)
               TlsFree(dwTlsIndex);
            DeleteCriticalSection(&csSync);
            sprintf(strInfo, "\n >>> DLL_PROCESS_DETACH Thread: %ld",
   GetCurrentThreadId());
            break;
         case DLL_THREAD_DETACH:
            vCleanUpTls();
            sprintf(strInfo, "\n >>> DLL_THREAD_DETACH Thread: %ld",
   GetCurrentThreadId());
            break;
      }
      printf(strInfo);
      return TRUE;
   }
   // 
   //    DLL function in the extended stored procedure to show TLS trap
   // 
   __declspec(dllexport) SRVRETCODE xp_Tls(SRV_PROC *pSrvProc)
   {
      char  strInfo[256]   =  "";
      char *   strData        =  NULL;
      sprintf(strInfo, "\n >>> Invoking xp_Tls on Thread: %ld",
   GetCurrentThreadId());
      printf(strInfo);
      if(TLS_FAIL != dwTlsIndex)
      {
         strData = TlsGetValue(dwTlsIndex);
         if(NULL != strData)
         {
            sprintf(strInfo, "\n >>> %s", strData);
            printf(strInfo);
         }
         else
         {
            printf("\n >>> *** Serious error *** TlsGetValue returned NULL,
   thread pooling not handled correctly.\n");
         }
      }
      return 1;
   }
				

Daha fazla bilgi

SQL Server 7.0 ve SQL Server 2000 Fiber

Biz kesinlikle TLS kullanarak engelleyin ve fiber modunda TLS kullanan tekrar yapmayı desteklemez. Fiber modunda, herhangi bir TLS güvenli değil hale getirme, çeşitli nedenlerle fiziksel iş parçacığının değiştirilebilir.

Bu makaledeki bilginin uygulandığı durum:
  • Microsoft SQL Server 2000 Enterprise Edition
  • Microsoft SQL Server 7.0 Standard Edition
  • Microsoft SQL Server 6.0 Standard Edition
  • Microsoft SQL Server 6.5 Standard Edition
Anahtar Kelimeler: 
kbmt kbhowto kbother kbprogramming kbusage KB163449 KbMttr
Otomatik TercümeOtomatik Tercüme
ÖNEMLİ: Bu makale, bir kişi tarafından çevrilmek yerine, Microsoft makine-çevirisi yazılımı ile çevrilmiştir. Microsoft size hem kişiler tarafından çevrilmiş, hem de makine-çevrisi ile çevrilmiş makaleler sunar. Böylelikle, bilgi bankamızdaki tüm makalelere, kendi dilinizde ulaşmış olursunuz. Bununla birlikte, makine tarafından çevrilmiş makaleler mükemmel değildir. Bir yabancının sizin dilinizde konuşurken yapabileceği hatalar gibi, makale; kelime dağarcığı, söz dizim kuralları veya dil bilgisi açısından yanlışlar içerebilir. Microsoft, içeriğin yanlış çevrimi veya onun müşteri tarafından kullanımından doğan; kusur, hata veya zarardan sorumlu değildir. Microsoft ayrıca makine çevirisi yazılımını sıkça güncellemektedir.
Makalenin İngilizcesi aşağıdaki gibidir:163449  (http://support.microsoft.com/kb/163449/en-us/ )