Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A többszálúság gondos programozást igényel. A legtöbb feladat esetében csökkentheti a bonyolultságot, ha sorba rendezi a végrehajtási kérelmeket a szálkészlet szálai alapján. Ez a témakör a nehezebb helyzetekkel foglalkozik, például több szál munkájának koordinálásával vagy a letiltott szálak kezelésével.
Megjegyzés:
A .NET-keretrendszer 4-től kezdve a feladat párhuzamos kódtára és a PLINQ olyan API-kat biztosít, amelyek csökkentik a többszálas programozás összetettségének és kockázatainak egy részét. További információ: Párhuzamos programozás a .NET-ben.
Holtpontok és versenyfeltételek
A többszálas megoldás az átviteli sebességgel és a válaszképességgel kapcsolatos problémákat oldja meg, de ezzel új problémákat vezet be: holtpontok és versenyhelyzetek.
Holtpontok
Holtpont akkor fordul elő, ha két szál mindegyike megpróbál zárolni egy erőforrást, amelyet a másik már zárolt. Egyik szál sem tud további haladást elérni.
A felügyelt szálkezelés osztályainak számos módszere időtúllépést biztosít a holtpontok észleléséhez. Az alábbi kód például megpróbál zárolást szerezni egy nevű lockObjectobjektumon. Ha a zárolást nem szerzik meg 300 milliszekundum alatt, Monitor.TryEnter visszatér false.
If Monitor.TryEnter(lockObject, 300) Then
Try
' Place code protected by the Monitor here.
Finally
Monitor.Exit(lockObject)
End Try
Else
' Code to execute if the attempt times out.
End If
if (Monitor.TryEnter(lockObject, 300)) {
try {
// Place code protected by the Monitor here.
}
finally {
Monitor.Exit(lockObject);
}
}
else {
// Code to execute if the attempt times out.
}
Versenyfeltételek
A versenyfeltétel egy olyan hiba, amely akkor fordul elő, ha egy program eredménye attól függ, hogy két vagy több szál közül melyik éri el először egy adott kódblokkot. A program többszöri futtatása különböző eredményeket eredményez, és egy adott futtatás eredménye nem jelezhető előre.
A versenyfeltételek egyszerű példája a mező növekménye. Tegyük fel, hogy egy osztály rendelkezik egy privát statikus mezővel (a Visual Basicben megosztva ), amely az osztály egy példányának létrehozásakor növekszik, például objCt++; a (C#) vagy objCt += 1 a (Visual Basic) kód használatával. Ehhez a művelethez be kell tölteni az értéket egy regiszterbeobjCt, növelni kell az értéket, és el kell őket tárolni.objCt
Többszálas alkalmazásokban előfordulhat, hogy egy olyan szál, amely betöltötte és megnövelte az értéket, egy másik szál előtagja lehet, amely mindhárom lépést végrehajtja; amikor az első szál folytatja a végrehajtást, és tárolja az értékét, felülírja objCt , anélkül, hogy figyelembe veszi, hogy az érték időközben megváltozott.
Ez a versenyfeltétel könnyen elkerülhető a(z) Interlocked osztály módszereivel, például a Interlocked.Increment. A többszálas adatszinkronizálás egyéb technikáiról a Többszálas adatok szinkronizálása című témakörben olvashat.
A versenyfeltételek akkor is előfordulhatnak, ha több szál tevékenységeit szinkronizálja. Amikor kódsort ír, figyelembe kell vennie, hogy mi történhet, ha egy szálat megszakítanak a sor (vagy a sort alkotó bármely gépi utasítás) végrehajtása előtt, és egy másik szál megelőzi azt.
Statikus tagok és statikus konstruktorok
Az osztály addig nem inicializálódik, amíg az osztálykonstruktor (C#-ban static, Visual Basicben Shared Sub New) le nem fut. Annak érdekében, hogy megakadályozzuk a kód végrehajtását egy nem inicializált típuson, a közös nyelvi futtatókörnyezet letiltja az osztály static tagjainak (illetve Visual Basic esetén a Shared tagoknak) más szálakból érkező összes hívását mindaddig, amíg az osztálykonstruktor nem futott le teljesen.
Ha például egy osztálykonstruktor új szálat indít el, és a menet eljárása meghívja az osztály egy static tagját, az új szál addig blokkol, amíg az osztálykonstruktor befejeződik.
Ez minden olyan típusra vonatkozik, amely konstruktort static tartalmazhat.
Processzorok száma
A többszálú architektúrára hatással lehet, hogy több processzor vagy csak egy processzor áll rendelkezésre egy rendszeren. További információ: Processzorok száma.
Használja a Environment.ProcessorCount tulajdonságot a futtatókörnyezetben elérhető processzorok számának meghatározásához.
Általános javaslatok
Több szál használatakor vegye figyelembe az alábbi irányelveket:
Ne használjon Thread.Abort más szálak megszakítására. Egy másik szál meghívása
Aborthasonló ahhoz, hogy kivételt dobjon az adott szálra anélkül, hogy tudná, hogy a szál milyen pontot ért el a feldolgozás során. A .NET 5 és újabb verzióiban a Thread.Abort elavult, és PlatformNotSupportedException kivételt okoz. Ehelyett használjon kooperatív lemondást a következőn keresztül: CancellationToken. További információ: SYSLIB0006: A Thread.Abort nem támogatott.Ne használja a Thread.Suspend és a Thread.Resume elemeket több szál tevékenységeinek szinkronizálására. Használja Mutex, ManualResetEvent, AutoResetEvent, és Monitor.
Ne szabályozza a munkaszálak végrehajtását a fő programból (például események használatával). Ehelyett úgy tervezze meg a programot, hogy a munkaszálak várhassák, amíg a munka elérhetővé válik, végrehajtsa, és ha végzett, értesítse a program más részeit. Ha a munkavégző szálak nem blokkolnak, fontolja meg a szálkészlet-szálak használatát. Monitor.PulseAll olyan helyzetekben hasznos, amikor a munkaszálak blokkolva vannak.
Ne használjon típusokat zárolási objektumként. Kerülje az olyan kódokat, mint a
lock(typeof(X))C#-ban vagy aSyncLock(GetType(X))Visual Basic-ben, vagy a Monitor.Enter használatát a Type objektumokkal. Egy adott típus esetében alkalmazástartományonként csak egy példány System.Type található. Ha a zárolás típusa nyilvános, a sajáttól eltérő kód zárolhatja azt, ami holtpontokhoz vezethet. További információkért tekintse meg a megbízhatósági legjobb gyakorlatokat.Óvatosan járjon el példányok zárolásakor, például a
lock(this)C# vagy aSyncLock(Me)Visual Basic nyelvben. Ha az alkalmazás más, típuson kívüli kódja zárolja az objektumot, holtpontok léphetnek fel.Győződjön meg arról, hogy a monitor objektumba belépett szálak mindig elhagyják ezt a monitor objektumot, akkor is, ha közben kivétel történik. A C# lock utasítás és a Visual Basic SyncLock utasítás automatikusan biztosítja ezt a viselkedést, egy végül blokk használatával annak érdekében, hogy a Monitor.Exit meghívásra kerüljön. Ha nem tudja biztosítani a kilépés meghívását, fontolja meg a terv módosítását a Mutex használatára. A rendszer automatikusan felszabadít egy mutexet, amikor a jelenleg tulajdonában lévő szál leáll.
Használjon több szálat a különböző erőforrásokat igénylő tevékenységekhez, és ne rendeljen több szálat egyetlen erőforráshoz. Az I/O-t érintő bármely feladatnak például előnye, hogy saját szála van, mivel ez a szál blokkolva lesz az I/O-műveletek során, és így lehetővé teszi más szálak végrehajtását. A felhasználói bemenet egy másik erőforrás, amely egy dedikált szál előnyeit élvezi. Egy egyprocesszoros számítógépen egy számításigényes feladat együtt létezik a felhasználói bemenetekkel és az I/O feladatokkal, de több számításigényes feladat egymással verseng.
Fontolja meg a Interlocked osztály metódusainak használatát egyszerű állapotváltozásokhoz a
lockutasítás helyett (SyncLockVisual Basicben). Azlockállítás jó általános célú eszköz, de az Interlocked osztály jobb teljesítményt nyújt az atomi frissítésekhez. Belsőleg egyetlen zárolási előtagot hajt végre, ha nincs ütközés. A kódismétlésekben figyelje meg az alábbi példákban láthatóhoz hasonló kódokat. Az első példában egy állapotváltozó növekszik:SyncLock lockObject myField += 1 End SyncLocklock(lockObject) { myField++; }Az Increment utasítás helyett a
lockmetódus használatával javíthatja a teljesítményt az alábbiak szerint:System.Threading.Interlocked.Increment(myField)System.Threading.Interlocked.Increment(myField);Megjegyzés:
Használja a metódust az Add 1-nél nagyobb atomi növekményekhez.
A második példában a referenciatípus változó csak akkor frissül, ha null értékű hivatkozás (
Nothinga Visual Basicben).If x Is Nothing Then SyncLock lockObject If x Is Nothing Then x = y End If End SyncLock End Ifif (x == null) { lock (lockObject) { x ??= y; } }A teljesítmény javítható az alábbiak szerint, ha inkább a CompareExchange módszert alkalmazzuk.
System.Threading.Interlocked.CompareExchange(x, y, Nothing)System.Threading.Interlocked.CompareExchange(ref x, y, null);Megjegyzés:
A CompareExchange<T>(T, T, T) metódus túlterhelése típusbiztos alternatívát kínál a referenciatípusokhoz.
Javaslatok osztálykódtárakhoz
Többszálú osztálykódtárak tervezésekor vegye figyelembe az alábbi irányelveket:
Ha lehetséges, kerülje a szinkronizálás szükségességét. Ez különösen igaz az erősen használt kódokra. Előfordulhat például, hogy egy algoritmus úgy van beállítva, hogy elviseljen egy versenyhelyzetet ahelyett, hogy megszüntetné azt. A szükségtelen szinkronizálás csökkenti a teljesítményt, és holtpontok és versenyfeltételek lehetőségét teremti meg.
A statikus adatok (
Shareda Visual Basicben) szál biztonságossá tétele alapértelmezés szerint.Alapértelmezés szerint ne tegye biztonságossá a példány adatszálát. A szálbiztos kód létrehozásához zárolt elemek hozzáadása csökkenti a teljesítményt, növeli a zárolási versengést, és lehetővé teszi a holtpontok előfordulását. A gyakori alkalmazásmodellekben egyszerre csak egy szál hajtja végre a felhasználói kódot, ami minimálisra csökkenti a szálbiztonság szükségességét. Ezért a .NET-osztálykódtárak alapértelmezés szerint nem biztonságosak.
Kerülje a statikus állapotot módosító statikus metódusok megadását. A gyakori kiszolgálói forgatókönyvekben a statikus állapot meg van osztva a kérelmek között, ami azt jelenti, hogy egyszerre több szál is végrehajthatja ezt a kódot. Ez lehetőséget ad a szálhibák megjelenésére. Fontolja meg egy olyan tervezési minta használatát, amely adatokat zár be olyan példányokba, amelyeket nem osztanak meg a kérések között. Továbbá ha a statikus adatok szinkronizálva vannak, az állapotot módosító statikus metódusok közötti hívások holtpontot vagy redundáns szinkronizálást eredményezhetnek, ami hátrányosan befolyásolhatja a teljesítményt.