Net

c # effektiv trådsikkerhedskø ConcurrentQueue

C Efficient Thread Safety Queue Concurrentqueue



Enqueue, Dequeue, IsEmpty, Få antallet af elementer i køen (Count).

For det første den interne struktur af ConcurrentQueue:



wps_clip_image-30166



1. Implementeringsprincip



Som vi alle ved, er der to implementeringer af almindelige ikke-trådsikre køer:

1. En cirkulær kø implementeret ved hjælp af arrays.

2. Køer implementeret ved hjælp af sammenkædede lister.



Se først på fordele og ulemper ved de to måder:

Implementeringen af ​​den fælles kø i .Net Farmework bruger den første metode. Ulempen er, at når køpladsen er utilstrækkelig, udføres udvidelsen. Hovedimplementeringen af ​​udvidelsen er at åbne et nyt array med en original længde på 2 gange og derefter kopiere dataene i det originale array. I det nye array vil der ikke være nogen lille hukommelsesoverhead, når de udvides, og indvirkningen på ydeevnen i et samtidig miljø kan ikke undervurderes. Når du ringer til konstruktøren af ​​kø, kan du selvfølgelig angive størrelsen på standardrummet. Mængden af ​​data er imidlertid uforudsigelig under normale omstændigheder. Hvis du vælger stort, spilder det plads. Hvis du vælger lille, vil der være overhead til kopiering af hukommelse, og du skal udvide køen efter udvidelse. Metoden TrimToSize () kaldes til at genvinde ubrugt hukommelsesplads.

Den anden implementering af den sammenkædede liste eliminerer problemet med spildt rum, men øger trykket fra GC. Når køen indtastes, tildeles en ny node. Når køen afskaffes, kasseres noden. For et stort antal dequeue-operationer er denne implementering ikke særlig effektiv.

Ved at kombinere de ovennævnte to implementeringer bruger ConcurrentQueue konceptet med segmenteret lagring (som vist i figuren ovenfor), når de understøtter flere tråde og udsteder teams i teamet. ConcurrentQueue tildeler hukommelse i enheder af segmenter, et segment. Den interne indeholder en matrix med en standardlængde på 32 og en markør til at udføre det næste segment. Der er et hoved og en halemarkør, der peger på henholdsvis start- og slutsegmentet. Denne struktur ligner noget operativsystemets segmenthukommelsesstyring og sidehukommelse. Ledelsesstrategi). Denne måde at allokere hukommelse på reducerer ikke kun trykket fra GC, men også den, der ringer op, bruger ikke TrimToSize () -metoden til at vise hukommelsen. (Når et bestemt hukommelsessegment er tomt, vil GC genvinde hukommelsessegmentet).

2. segmentets interne struktur

Faktisk er driften af ​​ConcurrentQueue faktisk driften af ​​segmentet.

Segment kan abstrakte følgende datastruktur:

wps_clip_image-5493

De vigtigste metoder inden for segmentet:

wps_clip_image-6121

Indersiden af ​​segmentet svarer til den normale kø implementeret af arrayet, bortset fra at atomoperationen bruges til at forhindre multi-thread konkurrenceproblemet for enqueue og dequeue operationer, og teknikken som tilfældig koncession bruges til at sikre livelock, og implementeringsmekanismen og ConcurrentStack er ikke meget anderledes. Implementeringsoplysningerne for mange TryAppends er meget klare i kildekommentarerne. Der er ikke mere forklaring her.

For det andet driften af ​​holdet

wps_clip_image-24139

Som vist i figuren ovenfor udføres enqueue-operationen i det bageste segment. Når dataene fejler i segmentet, udfører de først en tilbageførselsoperation og prøver derefter igen, indtil de lykkes. Årsagen til fejlen her (tail.Append (item) returnerer falsk. Den ene er, at når pladsen i segmentet ikke er nok, tildeles et nyt segment, og de elementer, der kommer ind i segmentet, mislykkes i løbet af denne tid.

For det tredje holddriften

wps_clip_image-3291

Som vist i ovenstående figur, når holdet fejler, returnerer det falsk i stedet for at spole tilbage som et hold. Fordi årsagen til teamfejl er, at når alle elementerne i køen er tomme, er holdet designet til at returnere bool. Funktionen af ​​værdien.

For det fjerde skal du afgøre, om den er tom (IsEmpty)

Den samlede bedømmelse er kompleksiteten af ​​O (1). Der er tre hovedsituationer:

1. Hovedknudepunktet (segment) er ikke nul og returnerer falsk

2. Hovedknudepunktet er tomt, og det næste knudepunkt er også tom for at returnere sandt

3. Hovedknudepunktet er tomt, og det næste knudepunkt er ikke tomt og returnerer falsk. Dette indikerer, at køen udvides, så du skal vente på, at udvidelsen fuldender dommen igen.

Fem, få antallet af elementer i køen (Count)

wps_clip_image-31544

Find hovedknudepunktets lave position og haleknudepunktets høje position. Da indekset for det aktuelle segment i køen er registreret i hvert segment, er det let at finde antallet af elementer i hele køen.

Som med ConcurrentStack indikerer den officielle Microsoft-dokumentation og kommentarer også, at det at bedømme, om køen er tom eller ikke bruger IsEmpty-attributten i stedet for at tælle Count == 0. Årsagen er, at GetHeadTailPositions ser efter placeringen af ​​hoved- og halenoder i proces med at verve og afskaffe en stor mængde data. Tidskrævende operationer, for kontinuerligt at løkke for at bestemme positionen for hoved- og halknudepunkterne, så afgør, om køen er tom eller brug IsEmpty-attributten.