Sdílet prostřednictvím


Předcházení kolizi haldy

Výchozí správci řetězců, které poskytuje MFC a ATL, jsou jednoduché obálky nad globální haldou. Tato globální halda je plně bezpečná pro vlákna, což znamená, že více vláken může přidělit a uvolnit paměť současně bez poškození haldy. Aby se zajistilo zabezpečení vlákna, halda musí serializovat přístup k sobě. To se obvykle provádí pomocí kritického oddílu nebo podobného mechanismu uzamčení. Pokaždé, když se dvě vlákna pokusí získat přístup k haldě současně, je jedno vlákno blokováno, dokud se nedokončí požadavek druhého vlákna. U mnoha aplikací k této situaci dochází zřídka a dopad na výkon zamykacího mechanismu haldy je zanedbatelný. U aplikací, které často přistupují k haldě z několika kolizí podprocesů pro zámek haldy, ale může dojít k pomalejšímu spuštění aplikace, než kdyby byla jednovláknová (dokonce i na počítačích s více procesory).

Aplikace, které používají CStringT , jsou zvláště náchylné ke kolizí haldy, protože operace s CStringT objekty často vyžadují relokaci vyrovnávací paměti řetězce.

Jedním ze způsobů, jak zmírnit kolize haldy mezi vlákny, je mít každé vlákno přidělovat řetězce z privátní haldy místní podprocesu. Pokud jsou řetězce přidělené s alokátorem konkrétního vlákna použity pouze v daném vlákně, alokátor nemusí být bezpečný pro přístup z více vláken.

Příklad

Následující příklad ukazuje proceduru vlákna, která přiděluje vlastní privátní haldu bez vláken, která se má použít pro řetězce v tomto vlákně:

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);
}

Komentáře

Pomocí stejného postupu vlákna může být spuštěno více vláken, ale protože každé vlákno má vlastní haldu, mezi vlákny neexistuje žádná kolize. Kromě toho skutečnost, že každá halda není bezpečná pro přístup z více vláken, poskytuje měřitelný nárůst výkonu, i když je spuštěná jenom jedna kopie vlákna. To je výsledek haldy, která nepoužívá nákladné vzájemně uzamčené operace k ochraně před souběžným přístupem.

Pro složitější postup vlákna může být vhodné uložit ukazatel na správce řetězců vlákna v slotu místního úložiště vlákna (TLS). To umožňuje jiným funkcím volanému procedurou vlákna přístup ke správci řetězců vlákna.

Viz také

Správa paměti pomocí CStringT