Gå til innhold

Spørsmål om multithread synkronisering (windows)


Anbefalte innlegg

Jeg har en DLL fil som skal ha støtte for flere tråder og siden jeg har veldig liten erfaring med dette og med tanke på vanskeligheten med å feilsøke på slik feil så har jeg et spørsmål.

 

Jeg har en klasse som ligger rundt en socket og den har to funksjoner der synkronisering må brukes.

 

UpdateSending og AddPacket

 

UpdateSending oppdaterer sendingen av pakker som AddPacket legger der.

 

Slik jeg har valgt å gjøre det er at jeg har to stk. std::vector som pakke beskrivelser ligger i og en peker som peker på den vektoren som AddPacket skal bruke. Når UpdateSending skjer så bytter den pekeren (pCurrentPacketBuffer) fra den ene vectoren til den andre dette gjøres med InterlockedExchange/InterlockedExchange64 (Windows spesifikk for 32 og 64bit) så den skal være grei. På slutten av AddPacket ligger følgende:

 

pCurrentPacketBuffer->push_back(PacketInfo);

 

Så det jeg lurer på er om det er noen finurligheter som gjør at funksjonen over kan bli kjørt etter at pekerne har blitt byttet om. Andre fiffie løsninger på problemet motaes også.

 

Jeg programmerer da under winXP og winxp x64

 

Takker på forhånd for alle svar.

Endret av Giddion
Lenke til kommentar
Videoannonse
Annonse

Spørsmålet her er først og fremst i hvilke tilfeller pointeren skifter mål. At du bruker en lock-variant for å endre selve adressen har ikke enormt mye å si (på x86 / x64, i hvertfall), siden endringen av minneadresse uansett er en atomisk operasjon, og pipelinen ikke vil tillate at to cpuer / cores jobber mot ulike "utgaver" av denne adressen. Sånn sett ville jeg heller satt min lit til et biprodukt av IXCHG; at variablen må være volatile, og dermed ikke optimaliseres eller caches av kompilatoren.

 

I alle tilfeller ville du nok hatt bedre nytte av et design med låsobjekter for én eller flere pakke-køer, slik at du får en klar og tydelig rekkefølge på tilgangen.

Lenke til kommentar

Takker og bukker einaros det er godt og se at du fortsatt er på forumet.

 

Du hadde helt rett i at skriving til 32bit er en atomic opperasjon på en 32bit cpu jeg må ha rota mye når jeg la inn interlock. Jeg går nok for bruken av volatile i dette tilfellet, men det er flere andre steder i programmet der jeg helt klart må bruke locking i en eller annen form og da kommer nok artikkel din til å bli veldig god å ha med seg.

Lenke til kommentar

Locking må du ha, men det er viktig å være klar over forskjellen på å bruke f.eks. mutexer, vs. å bruke instruksjoner med lock-prefix. Den sistnevnte typen locks beskytter ikke en seksjon av koden din; den sørger bare for at data man skriver til minnet ikke caches av cpuen. Måten dette gjøres på varierer nok fra arkitektur til arkitektur, men kort fortalt legges det beslag på pipelinen, instruksjonscachen tømmes og data skrives ned til fysisk minne. Problemet med dette er at det ofte medfører mer trøkk enn man behøver mot minne / cache. For cpuarkitektur som støtter såkalte "snooping"-protokoller vil to fysiske cpuer (og dermed to fysiske cacher) lytte etter forandringer i hverandre. Du vil derfor aldri oppleve å ha to forskjellige utgaver av samme variabel, cachet i de to forskjellige cpuene. Siden operasjonen i tillegg er atomisk, finnes det heller ingen sjanse for at én cpu leser eller skriver ut f.eks. halve pekere.

 

Mutexer, semaphorer, critical sections osv. brukes derimot til sperring av hele kodeblokker (flere instruksjoner). Hvis du f.eks. har tre tråder, og to køer, vil du (sånn jeg har forstått designet ditt) for den første tråden skrive mot vektor A. Når tråd nummer to får data, byttes pekeren til vektor B, og data skrives dit. Hvis den tredje tråden så får data inn, mens A og B fremdeles blir oppdatert, hjelper det fint lite at selve pekeren blir endret på en "trygg måte"; den første og tredje tråden vil begge jobbe mot vektor A -- samtidig. For å motvirke dette kan du assosiere låsobjekter med hver vektor, sånn at A og B kan bli modifisert av hver sin tråd simultant, mens alle andre påfølgende tråder må vente til plassen blir ledig.

Lenke til kommentar
Klikk for å se/fjerne innholdet nedenfor
Locking må du ha, men det er viktig å være klar over forskjellen på å bruke f.eks. mutexer, vs. å bruke instruksjoner med lock-prefix. Den sistnevnte typen locks beskytter ikke en seksjon av koden din; den sørger bare for at data man skriver til minnet ikke caches av cpuen. Måten dette gjøres på varierer nok fra arkitektur til arkitektur, men kort fortalt legges det beslag på pipelinen, instruksjonscachen tømmes og data skrives ned til fysisk minne. Problemet med dette er at det ofte medfører mer trøkk enn man behøver mot minne / cache. For cpuarkitektur som støtter såkalte "snooping"-protokoller vil to fysiske cpuer (og dermed to fysiske cacher) lytte etter forandringer i hverandre. Du vil derfor aldri oppleve å ha to forskjellige utgaver av samme variabel, cachet i de to forskjellige cpuene. Siden operasjonen i tillegg er atomisk, finnes det heller ingen sjanse for at én cpu leser eller skriver ut f.eks. halve pekere.

 

Mutexer, semaphorer, critical sections osv. brukes derimot til sperring av hele kodeblokker (flere instruksjoner). Hvis du f.eks. har tre tråder, og to køer, vil du (sånn jeg har forstått designet ditt) for den første tråden skrive mot vektor A. Når tråd nummer to får data, byttes pekeren til vektor B, og data skrives dit. Hvis den tredje tråden så får data inn, mens A og B fremdeles blir oppdatert, hjelper det fint lite at selve pekeren blir endret på en "trygg måte"; den første og tredje tråden vil begge jobbe mot vektor A -- samtidig. For å motvirke dette kan du assosiere låsobjekter med hver vektor, sånn at A og B kan bli modifisert av hver sin tråd simultant, mens alle andre påfølgende tråder må vente til plassen blir ledig.

8729994[/snapback]

 

hmm.. du har nok misforstått litt av designet mitt.

Jeg har to tråder (1 og 2) og to vectorer (A og B) de to trådene skal jobbe på ulike vectorer.

 

Tråd 1 forsyner vector A med pakker.

Tråd 2 jobber på vector B.

Når tråd 2 er ferdig med jobbingen tømmes på vector B tømmes vector B og vectoren byttes slik at tråd 1 forsyner vector B med pakker mens tråd 2 jobber med pakkene i vector A

 

Tråd 1 kan godt være flere tråder og da må jeg helt klart lage en låse mekanisme hvis jeg bruker vector eller lignende, men det var egentlig ikke en del av problemet.

 

Takker for svar.

Lenke til kommentar

Aha, vel, svaret mitt blir fortsatt relevant :) Si at Tråd 1 begynner å ta i mot en pakke, og dermed begynner oppdatering av vector A. Samtidig med dette har Tråd 2 begynt fullført behandling av vector B, så pekeren byttes. Når Tråd 2 så begynner arbeid mot vector A, er det stor sjanse for at noe tryner -- siden Tråd 1 fremdeles står midt i en oppdatering der. Først når Tråd 1 har fullført sin oppdatering av vector A, bør pekeren kunne byttes over.

Lenke til kommentar
Aha, vel, svaret mitt blir fortsatt relevant :) Si at Tråd 1 begynner å ta i mot en pakke, og dermed begynner oppdatering av vector A. Samtidig med dette har Tråd 2 begynt fullført behandling av vector B, så pekeren byttes. Når Tråd 2 så begynner arbeid mot vector A, er det stor sjanse for at noe tryner -- siden Tråd 1 fremdeles står midt i en oppdatering der. Først når Tråd 1 har fullført sin oppdatering av vector A, bør pekeren kunne byttes over.

8735995[/snapback]

 

hmm... den hadde jeg ikke tenkt på :(

Da blir det låsing da.. det hadde jeg håpet å slippe..

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...