Freigeben über


Vermeiden von Heapkonflikten

Die von MFC und ATL bereitgestellten Standardzeichenfolgenmanager sind einfache Wrapper über einem globalen Heap. Dieser globale Heap ist vollständig threadsicher, was bedeutet, dass mehrere Threads gleichzeitig Arbeitsspeicher von ihm zuweisen und freigeben können, ohne den Heap zu beschädigen. Um Threadsicherheit zu gewährleisten, muss der Heap den Zugriff auf sich selbst serialisieren. Dies wird in der Regel mit einem kritischen Abschnitt oder einem ähnlichen Sperrmechanismus erreicht. Wenn zwei Threads gleichzeitig versuchen, auf den Heap zuzugreifen, wird ein Thread blockiert, bis die Anforderung des anderen Threads abgeschlossen ist. Bei vielen Anwendungen tritt diese Situation selten auf, und die Leistungsauswirkungen des Sperrmechanismus des Heaps sind vernachlässigbar. Bei Anwendungen, die häufig über mehrere Threads auf den Heap zugreifen, kann die Anwendung jedoch langsamer ausgeführt werden, als wenn sie singlethreads (auch auf Computern mit mehreren CPUs) ausgeführt wurde.

Anwendungen, die CStringT verwenden, sind besonders anfällig für Heap-Inhalte, da Vorgänge für CStringT Objekte häufig eine Neuansiedlung des Zeichenfolgenpuffers erfordern.

Eine Möglichkeit, heap-Konflikte zwischen Threads zu verringern, besteht darin, dass jeder Thread Zeichenfolgen aus einem privaten, threadlokalen Heap zuweist. Solange die Zeichenfolgen, die dem Allocator eines bestimmten Threads zugeordnet sind, nur in diesem Thread verwendet werden, muss der Allocator nicht threadsicher sein.

Beispiel

Das folgende Beispiel veranschaulicht eine Threadprozedur, die einen eigenen privaten, nicht threadsicheren Heap zuweist, der für Zeichenfolgen in diesem Thread verwendet werden soll:

DWORD WINAPI WorkerThreadProc(void* pBase)
{
   // Declare a non-thread-safe heap just for this thread:
   CWin32Heap stringHeap(HEAP_NO_SERIALIZE, 0, 0);

   // Declare a string manager that uses the thread's heap:
   CAtlStringMgr stringMgr(&stringHeap);

   int nBase = *((int*)pBase);
   int n = 1;
   for(int nPower = 0; nPower < 10; nPower++)
   {
      // Use the thread's string manager, instead of the default:
      CString strPower(&stringMgr);

      strPower.Format(_T("%d"), n);
      _tprintf_s(_T("%s\n"), strPower);
      n *= nBase;
   }

   return(0);
}

Kommentare

Mehrere Threads können mit dieser gleichen Threadprozedur ausgeführt werden, da jeder Thread jedoch über einen eigenen Heap verfügt, gibt es keinen Inhalt zwischen Threads. Darüber hinaus gibt die Tatsache, dass jeder Heap nicht threadsicher ist, eine messbare Leistungssteigerung, auch wenn nur eine Kopie des Threads ausgeführt wird. Dies ist das Ergebnis des Heaps, der keine teuren verriegelten Vorgänge verwendet, um vor gleichzeitigen Zugriff zu schützen.

Bei einer komplizierteren Threadprozedur kann es praktisch sein, einen Zeiger auf den Zeichenfolgen-Manager des Threads in einem Threadspeicherplatz (Local Storage, TLS) zu speichern. Dadurch können andere Funktionen, die von der Threadprozedur aufgerufen werden, auf den Zeichenfolgen-Manager des Threads zugreifen.

Siehe auch

Speicherverwaltung mit CStringT