Permalänk
Medlem

C# Trådsäkerhet

Hejsan.

Jag sitter och experimenterar med ett program lite grann i C# .NET 4.0.

Nu finns ju intressant stöd för parallell-programmering i .NET. Det finns också trådsäkra alternativ till List och Dictionary med flera.

Min fråga är när det är okej att använda en vanliga lista och när man måste använda en som är säker för exekvering med parallella trådar.

Ta denna kod till exempel:

int[] minArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; int räknare = 0; List<int> minLista = new List<int>(); Parallel.Invoke( () => { for(int i = 0 ; i < 5 ; i++) { räknare += minArray[i]; minLista.Add(minArray[i]); } }, () => { for(int i = 5 ; i < 10 ; i++) { räknare += minArray[i]; minLista.Add(minArray[i]); } } );

Är det okej att på det viset både skriva till enkla typer som int (räknare), lägga till saker till listor (minLista) och läsa från ej-trådsäkra samlingar (minArray)?

Alternativt finns ju ConcurrentBag som jag skulle kunna använda istället för listan, den är ju speciellt framtagen för att användas parallellt.

Jag känner mig osäker på när något förstör för programmet, när något kommer söla ner programmet på grund av synkroniseringar och när något är helt okej att göra.

Vad jag förstått går det i varje fall att ha trådar som läser från en gemensam lista utan att det blir strul, men segar det ned programmet om man inte specificerat att listan är read-only på något vis?

I mitt program har jag också ett stort antal trådar som behandlar data och sedan lägger till resultatet till en lista. Denna lista läses aldrig inifrån trådarna utan de skriver bara till den. Den läses inte förän programmet är tillbaka till att bara exekvera i en tråd, fungerar det att göra så eller bör jag använda ConcurrentBag istället för List?

Permalänk
Medlem

Skrivningar till gemensamma (mutable) datastrukturer är osäkra i en osynkroniserad miljö. Säg att du till exempel har listan [1, 2] och en tråd vill lägga till elementet '3' i slutet samtidigt som en annan vill lägga till elementet '5' på samma position. Om bägge trådar råkar köras exakt samtidigt och bestämmer sig för att listan är 2 enheter lång kommer de i bästa fall skriva över varandra, och i värsta fall försöka förlänga samma lista för att göra ny plats för sitt element.

Däremot kan du läsa fritt från en osynkroniserad lista om du inte skriver till den samtidigt. Om det inte är superviktigt att datan är uppdaterad vid läsning kan du även låta en tråd skriva samtidigt som flera läser (så länge du inte förlänger listan åtminstone.)

Visa signatur

Kom-pa-TI-bilitet

Permalänk

Är själv ganska dålig på trådar och har inte jobbat med det så mycket, men hittade en tråd som kanske passar denna tråd!
http://stackoverflow.com/questions/2980283/thread-safe-collec...

Permalänk

Trådsäkerhet i parallellisering är ingen skillnad gentemot vid andra tillfällen. Du måste givetvis hantera synkroniseringsproblem vid läsning och skrivning om du vill slippa problem. Och precis som du skriver är inte List<T> trådsäker därmed svarar frågan på sig själv att du måste antligen använda en trådsäker lista eller använda någon form av lock vid användning av listan.

Permalänk
Medlem

Som sagt skulle jag sätta locks i din lista och det heter väll just lock om jag inte minns fel som man kan använda på exempelvis ett dummyobject. Jag vet ej hur invoke fungerar exactly till main eller guitrådar, när avbrytningarna tillåts, då man får uppdatera guikomponenter till exempel. Kommer ihåg att jag satt och pula med volatile variabler i samband med trådningen vilket kändes lite oklart, nu är oklarheten till baka igen

Lägga locks är förvånansvärt lätt iaf
Fanns exempel i balls of steel's länk.

Permalänk
Medlem

Tack för era synpunkter, de bekräftar en del som jag också läst på annat håll.

Skrivet av Micke1984:

Trådsäkerhet i parallellisering är ingen skillnad gentemot vid andra tillfällen. Du måste givetvis hantera synkroniseringsproblem vid läsning och skrivning om du vill slippa problem.

Givetvis. Och det är jag medveten om. Min fundering är mer när synkroniseringsproblem uppstår och när man kan komma undan utan att använda lås som saktar ned. Exempelvis om jag har en lista som jag enbart läser ifrån från ett antal trådar kanske jag inte behöver låsa eller bry mig om synkronisering.

Ett annat scenario är om jag har en mängd trådar som vill lägga till sina resultat i en lista. Vilka problem uppstår då och hur gör man det bäst. Exempelvis så läste jag om ConcurrentBag att den fungerar bäst när en tråd både läser och skriver till den. Om trådar bara skriver var den inte alls lika effektiv och det stod att man fick samma synkroniseringsproblem som med en lista med lås. Fast sen finns det väl sätt att mellanlagra resultat från varje tråd och inte slå ihop dem förän tråden är klar.

Permalänk
Medlem
Skrivet av Teknocide:

Om det inte är superviktigt att datan är uppdaterad vid läsning kan du även låta en tråd skriva samtidigt som flera läser (så länge du inte förlänger listan åtminstone.)

Enbart om läs- och skrivoperationerna är atomic, annars kan du få en blandning av gammal och ny data när du läser ett element från listan vilket inte är så lyckat.

Visa signatur

Assembly är ett högnivåspråk.

Permalänk
Skrivet av jucce:

Tack för era synpunkter, de bekräftar en del som jag också läst på annat håll.

Givetvis. Och det är jag medveten om. Min fundering är mer när synkroniseringsproblem uppstår och när man kan komma undan utan att använda lås som saktar ned. Exempelvis om jag har en lista som jag enbart läser ifrån från ett antal trådar kanske jag inte behöver låsa eller bry mig om synkronisering.

Ju mindre access ju mindre risk. Dock så kan jag lova dig om risken finns så händer det Ett bra sätt att se det framför sig är att göra ett enhets test som du anropar flera gånger (100+). Då kommer du se att påverkar då och då men oftast funkar bra. För min del när jag testade så failade var tionde gång.

Och för övrigt om du har en kontrollerat senario där du är 100% på du bara kommer läsa ifrån listan och aldrig skriva till den samtidigt (tex att listan fylls på innan eller något) så borde du klara dig utan lock då du inte påverkar listan.