Szálkészletek

A szálkészlet feldolgozószálak gyűjteménye, amelyek hatékonyan hajtanak végre aszinkron visszahívásokat az alkalmazás nevében. A szálkészlet elsősorban az alkalmazásszálak számának csökkentésére és a feldolgozószálak felügyeletére szolgál. Az alkalmazások sorba állíthatják a munkaelemeket, a munkát várakoztatható leírókhoz rendelhetik, időzítő alapján automatikusan sorba állíthatják, és I/O-műveletekhez köthetik.

Szálkészlet-architektúra

A következő alkalmazások használhatnak szálkészletet:

  • Egy rendkívül párhuzamos alkalmazás, amely nagy számú kis munkaelemet képes aszinkron módon elküldeni (például elosztott indexkeresést vagy hálózati I/O-t).
  • Olyan alkalmazás, amely nagy számú szálat hoz létre és pusztít el, amelyek mindegyike rövid ideig fut. A szálkészlet használata csökkentheti a szálkezelés összetettségét, valamint a szálak létrehozásának és megsemmisítésének többletterhelését.
  • Olyan alkalmazás, amely független munkaelemeket dolgoz fel a háttérben és párhuzamosan (például több lap betöltése).
  • Olyan alkalmazás, amely kizárólagos várakozást kell végrehajtania a kernelobjektumokon, vagy blokkolnia kell a bejövő eseményeket egy objektumon. A szálkészlet használata csökkentheti a szálkezelés összetettségét, és növelheti a teljesítményt a környezeti kapcsolók számának csökkentésével.
  • Olyan alkalmazás, amely testreszabott várakozó szálakat hoz létre, hogy eseményekre várakozzanak.

Az eredeti szálkészlet teljesen újra lett tervezve a Windows Vista rendszerben. Az új szálkészlet azért lett továbbfejlesztve, mert egyetlen feldolgozószáltípust biztosít (az I/O-t és a nem I/O-t is támogatja), nem használ időzítőszálat, egyetlen időzítősort biztosít, és dedikált állandó szálat biztosít. Emellett tisztítási csoportokat, nagyobb teljesítményt, folyamatonként több készletet is biztosít, amelyek egymástól függetlenül vannak ütemezve, és egy új szálkészlet API-t is biztosít.

A szálkészlet architektúrája a következőkből áll:

  • A visszahívási függvényeket végrehajtó feldolgozószálak
  • Több wait handle-re várakozó szálak
  • Munkasor
  • Az egyes folyamatok alapértelmezett szálkészlete
  • Feldolgozó-előállító, amely a feldolgozói szálakat kezeli

Ajánlott eljárások

Az új szálkészlet API- nagyobb rugalmasságot és vezérlést biztosít, mint az eredeti szálkészlet API-. Van azonban néhány apró, de fontos különbség. Az eredeti API-ban a várakozás visszaállítása automatikus volt; az új API-ban a várakozást minden alkalommal explicit módon alaphelyzetbe kell állítani. Az eredeti API automatikusan kezelte a megszemélyesítést, és átadta a hívási folyamat biztonsági környezetét a szálnak. Az új API-val az alkalmazásnak explicit módon kell beállítania a biztonsági környezetet.

A következők bevált gyakorlatok a szálkészlet használatakor:

  • A folyamat szálai egy közös szálkészletet használnak. Egyetlen feldolgozószál egyszerre több visszahívási függvényt is végrehajthat. Ezeket a munkaszálakat a szálkészlet kezeli. Ezért ne fejezzen be egy szálat a szálkészletből úgy, hogy meghívja TerminateThread a szálon, vagy meghívja ExitThread egy visszahívási függvényből.

  • Az I/O-kérések a szálkészlet bármely szálán futtathatók. A szálkészlet-szál I/O-jának megszakítása szinkronizálást igényel, mert előfordulhat, hogy a megszakítási függvény az I/O-kérést kezelő száltól eltérő szálon fut, ami egy ismeretlen művelet törlését eredményezheti. Ennek elkerülése érdekében mindig adja meg azt a ÁTFEDÉSBEN lévő struktúrát, amellyel I/O-kérést indítottak CancelIoEx aszinkron I/O meghívásakor, vagy a saját szinkronizálásával győződjön meg arról, hogy a CancelSynchronousIo vagy CancelIoEx függvény meghívása előtt ne lehessen más I/O-t elindítani a célszálon.

  • Törölje a visszahívási függvényben létrehozott összes erőforrást, mielőtt visszatér a függvényből. Ezek közé tartozik a TLS, a biztonsági környezetek, a szál prioritása és a COM-regisztráció. A callback függvénynek a visszatérés előtt vissza kell állítania a szál állapotát is.

  • Tartsa életben a várakozási fogópontokat és a hozzájuk tartozó objektumokat, amíg a szálkészlet nem jelzi, hogy az elkészült a fogóponttal.

  • Jelölje meg az összes olyan szálat, amely hosszadalmas műveletekre vár (például I/O-kiürítések vagy erőforrás-törlés), hogy a szálkészlet új szálakat foglalhassa le ahelyett, hogy erre várna.

  • Mielőtt eltávolítana egy, a szálkészletet használó DLL-t, szakítsa meg az összes munkaelemet, I/O-t, várakozási műveletet és időzítőt, és várja meg a visszahívások végrehajtását.

  • Kerülje el a holtpontokat a munkaelemek és a visszahívások közötti függőségek megszüntetésével, annak biztosításával, hogy egy visszahívás ne várjon saját maga befejeződésére, valamint a szál prioritásának megőrzésével.

  • Ne állítson túl sok elemet sorba túl gyorsan egy olyan folyamatban, amelyben más összetevők is az alapértelmezett szálkészletet használják. Minden folyamathoz, így a Svchost.exe-hez is, egy alapértelmezett szálkészlet tartozik. Alapértelmezés szerint minden szálkészlet legfeljebb 500 feldolgozószállal rendelkezik. A szálkészlet több feldolgozószálat próbál létrehozni, ha a kész/futó állapotban lévő munkaszálak számának kisebbnek kell lennie, mint a processzorok száma.

  • Kerülje a COM egyszálas lakásmodellt, mivel nem kompatibilis a szálkészlettel. Az STA olyan szálállapotot hoz létre, amely hatással lehet a szál következő munkaelemére. Az STA általában hosszú élettartamú, és szál affinitással rendelkezik, ami a szálkészlet ellentéte.

  • Hozzon létre egy új szálkészletet a szál prioritásának és elkülönítésének szabályozásához, egyéni jellemzők létrehozásához és a válaszképesség javításához. A további szálkészletek azonban több rendszererőforrást igényelnek (szálak, kernelmemória). A túl sok pool használata növeli a CPU-erőforrásokért való versengés kockázatát.

  • Ha lehetséges, a szálkészlet egyik szálának jelzésére APC-alapú mechanizmus helyett várakoztatható objektumot használjon. Az APC-k nem működnek olyan jól a szálkészlet-szálakkal, mint más jelzési mechanizmusok, mivel a rendszer szabályozza a szálkészlet szálainak élettartamát, így lehetséges, hogy egy szál le legyen állítva az értesítés kézbesítése előtt.

  • Használja a szálkészlet-hibakereső bővítményt, a !tp-t. Ez a parancs a következő használattal rendelkezik:

    • pool címjelzők
    • obj címjelzők
    • tqueue címjelzők
    • pincér cím
    • munkavégző címe

    A pool, a waiter és a worker esetében, ha a cím nulla, a parancs kiírja az összes objektumot. A pincér és a feldolgozó esetében a cím kihagyásával az aktuális szál törlődik. A következő jelzők vannak meghatározva: 0x1 (egysoros kimenet), 0x2 (tagok kiíratása) és 0x4 (a pool munkavárakozási sorának kiíratása).

Note

Modern alternatívák: C++/WinRT-alkalmazások esetén a Windows szálkészlete korutinokon keresztül érhető el – használja a co_await winrt::resume_background() elemet a feladatok szálkészletbe küldéséhez, a co_await winrt::resume_foreground(dispatcher) elemet pedig az UI-szálra való visszatéréshez. Ez strukturált egyidejűséget biztosít manuális visszahíváskezelés nélkül. A standard C++ kód esetében a std::asyncstd::launch::async szabályzat hordozható feladatalapú párhuzamosságot biztosít, bár közvetlenül nem használja a Windows szálkészletet.

Szálkészlet API

A szálkészlet-függvények használata