Gå til innhold

Spørsmål om pthread mutexes


Anbefalte innlegg

Hei

 

Lurer på om en mutex har ett slags kø-system

Hvis tråd 1,2,og 3 requester en mutex etter hverandre. Vil tråd 2 få mutexen når tråd 1 slipper, eller vil det være tilfeldig (timing).

 

Jeg spør fordi jeg har en prosessorintensiv tråd (tråd 1) med litt kjøretid og en del andre tråder som gjør andre ting.

 

Tråd 1 skal slippe å rerequeste en mutex mellom hver oppgave

 

Hvis tråd 1 blir matet med oppgaver kontinuerlig (alltid oppgaver i kø) får de andre trådene i applikasjonen aldri tilgang til mutexen.

 

Kunne innført en delay, men dette er uaktuelt da selv 1 ms vil ha for store ytelses slag mot programmet

 

Jeg tenker at siden tråd1 slipper og så re-requester mutexen rett etterpå har den en timing som tillater den å ta tilbake mutexen med en gang (mens de andre trådene på grunn av timing ikke får tilgang)

 

Tråd biblioteket som brukes er som sagt pthread, og plattformen er windows 7

 

Takker for eventuelle tanker og svar :)

Lenke til kommentar
  • 3 uker senere...
Videoannonse
Annonse

Jeg har aldri brukt pthreads før, men ut ifra hva jeg forstår så er det round robin, dvs ingen FIFO-kø på mutexes. Dette kan skape en del problemer, særlig det du nevner ("lock convoy", iflg. linken). Under står det en løsning på problemet, men det involverer at du lager en slags semafor inni kritiske delen.

 

http://stackoverflow.com/questions/5385777/implementing-a-fifo-mutex-in-pthreads

Lenke til kommentar
  • 2 uker senere...

Hvordan kommuniserer du oppgavene til trådene? Det kan godt hende jeg har misforstått hvordan du gjør dette.. Men velger uansett å komme med et svar ;)

 

Slik jeg forstår det, holder du locken under executinga av hele oppgaven. Dette vil jo nekte andre tråder å gjøre noe samtidig. I beste fall vil du alltid ha en prosess aktiv, mens de andre vil vente på mutex lock. Du vil egentlig alltid prøve å sørge for at mutexen ikke er holdt, slik at andre tråder får tilgang på den.

 

En vanlig måte er å bruke en kø (std::queue, med mutexer for å pushe og poppe), eventuelt bruke lockless queues, der man slipper hele problemet. Da vil alltid trådene som gir oppgaver pushe ting på køen, mens arbeidstrådene vil poppe av

 

om du har mulighet, har tbb (thread building blocks) gode og effektive implementasjoner av lockless queues, der du i trådene dine stort sett kan kalle while (queue.try_pop(..)) {} og ikke tenke stort mer over det.

 

om du kan beskrive litt mer om hva du prøver å oppnå og hva trådene gjør og hvordan du har strukturert det hele blir det nok lettere å komme med treffende svar ;)

Lenke til kommentar
' timestamp='1346673047' post='19624085']

Hvordan kommuniserer du oppgavene til trådene? Det kan godt hende jeg har misforstått hvordan du gjør dette.. Men velger uansett å komme med et svar ;)

 

Slik jeg forstår det, holder du locken under executinga av hele oppgaven. Dette vil jo nekte andre tråder å gjøre noe samtidig. I beste fall vil du alltid ha en prosess aktiv, mens de andre vil vente på mutex lock. Du vil egentlig alltid prøve å sørge for at mutexen ikke er holdt, slik at andre tråder får tilgang på den.

 

En vanlig måte er å bruke en kø (std::queue, med mutexer for å pushe og poppe), eventuelt bruke lockless queues, der man slipper hele problemet. Da vil alltid trådene som gir oppgaver pushe ting på køen, mens arbeidstrådene vil poppe av

 

om du har mulighet, har tbb (thread building blocks) gode og effektive implementasjoner av lockless queues, der du i trådene dine stort sett kan kalle while (queue.try_pop(..)) {} og ikke tenke stort mer over det.

 

om du kan beskrive litt mer om hva du prøver å oppnå og hva trådene gjør og hvordan du har strukturert det hele blir det nok lettere å komme med treffende svar ;)

 

Hei

Heter vel at det ikke finnes dårlige svar, bare dårlige spørsmål eller noe sånn, alle svar er jeg ihvertfall taknemmelig for.

 

Trådene blir ikke kommunisert oppgaver, det er egne tråder som jobber med sine egne ting i sin egen lille verden, men da dette ofte gir veldig fine konflikter gjorde jeg så de måtte ha en mutex for å få tilgang til ett objekt som er sentralt for hele applikasjonen.

 

Problemet oppstår ved at en tråd har veldig intensive oppgaver (tenk sjekking av >1000 sockets med krav om lav responstid til hver). Det gikk jo ikke at den holder på mutexen hele tiden så jeg gjorde så den slipper den etter en viss tid (kalkulert basert på en mengde variabler som klienter, tid per klient, krav om responstid etc). Og så re-requester den mutexen. Problemet er at dette går altfor fort, og man har ikke tid til å legge inn en pause heller da jeg ikke har råd å tape hastighet

 

Håper det var noe oppklarende. 40 i feber i dag så ble ikke mer utfyllende i dag desverre :)

Lenke til kommentar

Ok så problemet her er egentlig at du har et sjefsobjekt som egentlig alle (trådene) vil bruke hele tiden. Og siden du vil bruke det hele tida, vil du egentlig alltid holde locken til det.

 

Så du er i en tight loop når du gjør dette også releaser du mutexen for å la andre få en sjans?

 

Her høres det egentlig ut som du bør omstrukturere koden litt.

Trenger du egentlig holde locken til sjefsobjektet? Eller kan du lage threadsafe funksjonskall (uten alt for mye omskriving) på det, slik at trådene dine kan bruke objektet uten å tenke så mye på mutexer?

 

en annen idè kan jo være at du kan lage en kø, der de andre trådene plasserer requestene sine, også tar main tråden din å prosesserer det når den får tid. (dette vil sansynligvis føre til at main tråden din får for mye å gjøre).

 

"Det gikk jo ikke at den holder på mutexen hele tiden så jeg gjorde så den slipper den etter en viss tid"

En mutex/semafor er egentlig noe du aldri vil holde mer enn noen mikrosekunder. Siden det virker som om denne holdes lengre, bør du virkelig se på om du kan gjøre noe for å omstrukturere dette. Du vil jo kun holde locken så lenge du bruker objektet du holder til noe meningsfullt.

 

Et nyttig verktøy (uansett) for å profilere concurrency (og andre ting) er intel amplifier: http://software.intel.com/en-us/intel-vtune-amplifier-xe

De har en 30 dagers prøve der, slik at du kan teste det ut på applikasjonen din. Da kan du se nøyaktig over en tidslinje hvordan trådene kjemper om locks.

Lenke til kommentar
' timestamp='1346748175' post='19626938']

"Det gikk jo ikke at den holder på mutexen hele tiden så jeg gjorde så den slipper den etter en viss tid"

En mutex/semafor er egentlig noe du aldri vil holde mer enn noen mikrosekunder. Siden det virker som om denne holdes lengre, bør du virkelig se på om du kan gjøre noe for å omstrukturere dette. Du vil jo kun holde locken så lenge du bruker objektet du holder til noe meningsfullt.

 

Med en viss tid mente jeg rundt <5 millisekunder ved høyt antall tilkoblinger (I 20k området) og ikke-eksisterende ved lavt antall tilkoblinger (Dette gjelder stress-testing, en av hovedpunktene er at serveren skal holde god responstid selv med ekstreme antall tilkoblinger, men selv om den slipper veldig ofte (tenk 100 000 i sekundet) så hjelper det ikke da det blir re-requestet igjen med en gang av samme tråd. Det er kritiske variabler som blir brukt av alle trådene så mutex må nok brukes på dette objektet.

 

Kø-ideen liker jeg, men jeg tenker det må jo finnes noen lettere måter å gjøre det på

 

Takker for link til intel verktøyet, det skal jeg prøve.

Kan vel egentlig konkludere med at jeg har fått løsning på spørsmålet i tråden, da jeg vet hvorfor mutex hoggen kommer og hvordan jeg løser den. Holder den alikevel åpen da jeg syns jeg fikk gode innspill og kanskje noen andre vil komme med noen :)

 

Takk til både [Kami] og LostOblivion for gode svar, det hjalp mye på forståelsen :)

Lenke til kommentar

mutexer låses for en tråd om gangen og den som tar den først får den først, ingen tilfeldigheter der. Husk bare at mutex objekter opererer ikke bare mellom tråder men mellom prosesser også, om du ikke kjører flere prosesser samtidig så bruk heller en critical section, den er mye raskere, så kan du putte en spin count også.

Lenke til kommentar

Husk at det første du skal gjøre, og jeg mener det absolutt første du skal gjøre i et program er å vurdere om du behøver synkronisering i det hele tatt, den beste løsningen er alltid å unngå synkronisering. Men hvis det ikke lar seg gjøre, så må du tenke nøye gjennom hva du virkelig behøver. Å sette sammen et virkelig godt og effektivt synkroniseringssystem høres enkelt ut og noen ganger er det enkelt, men åpne paint og tegn bokser, skriv inni boksene "Semaphore" "Mutex" "Critical Section" "Event object" etc... etter hva du behøver og tenk virkelig nøye gjennom det, det beste er å tegne ned nodene, for så å fjerne alle unødvendige noder etterpå.

Lenke til kommentar

mutexer låses for en tråd om gangen og den som tar den først får den først, ingen tilfeldigheter der.

Kommer an på implementasjonen, men det er ikke normalt noen "ventekø" for en mutex, og dersom flere tråder venter, så skal det normalt være tilfeldig hvilken tråd som vil få neste lås på en mutex.

 

Dette kan jeg verifisere under .NET med følgende kode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace MutexTest
{
   class Program
   {
    private static readonly Mutex mutex = new Mutex();
    static void Main(string[] args)
    {
	    var builder = new StringBuilder();
	    mutex.WaitOne();
	    var threads = new List<Thread>(Enumerable.Range(0, 50).Select(i => new Thread(
			    () =>
				    {
					    mutex.WaitOne();
					    builder.AppendLine("Thread " + i + " locked the mutex.");
					    Thread.Sleep(50);
					    mutex.ReleaseMutex();
				    })));
	    threads.ForEach(th => th.Start());
	    Thread.Sleep(500);
	    mutex.ReleaseMutex();
	    threads.ForEach(th => th.Join());

	    string result = builder.ToString();
	    System.IO.File.WriteAllText("output.txt", result);
	    Console.Write(result);
	    Console.ReadKey();
    }

   }
}

resulterte i

 

Thread 48 locked the mutex.
Thread 13 locked the mutex.
Thread 49 locked the mutex.
Thread 0 locked the mutex.
Thread 41 locked the mutex.
Thread 11 locked the mutex.
Thread 44 locked the mutex.
Thread 15 locked the mutex.
Thread 40 locked the mutex.
Thread 10 locked the mutex.
Thread 36 locked the mutex.
Thread 2 locked the mutex.
Thread 3 locked the mutex.
Thread 14 locked the mutex.
Thread 37 locked the mutex.
Thread 4 locked the mutex.
Thread 7 locked the mutex.
Thread 8 locked the mutex.
Thread 43 locked the mutex.
Thread 5 locked the mutex.
Thread 47 locked the mutex.
Thread 12 locked the mutex.
Thread 31 locked the mutex.
Thread 1 locked the mutex.
Thread 42 locked the mutex.
Thread 17 locked the mutex.
Thread 45 locked the mutex.
Thread 9 locked the mutex.
Thread 25 locked the mutex.
Thread 6 locked the mutex.
Thread 33 locked the mutex.
Thread 18 locked the mutex.
Thread 20 locked the mutex.
Thread 30 locked the mutex.
Thread 29 locked the mutex.
Thread 22 locked the mutex.
Thread 16 locked the mutex.
Thread 34 locked the mutex.
Thread 26 locked the mutex.
Thread 23 locked the mutex.
Thread 46 locked the mutex.
Thread 38 locked the mutex.
Thread 21 locked the mutex.
Thread 39 locked the mutex.
Thread 32 locked the mutex.
Thread 35 locked the mutex.
Thread 28 locked the mutex.
Thread 19 locked the mutex.
Thread 27 locked the mutex.
Thread 24 locked the mutex.

 

edit: bedre resultat

Endret av GeirGrusom
Lenke til kommentar

Numrene på trådene ser forskjellige ut, men det er ingen tilfeldigheter der likevel. :)

De får ikke lås i den rekkefølgen de spør etter det. Jeg får kanskje endre ordlegging: Fra programmets synspunkt er det ikke deterministisk hvilken tråd som vil klare å låse en mutex dersom mange tråder har bedt om låsen sekvensielt. Det er first-come-first serve. Den første tråden som svarer på signal er den som får låst opp mutexen. Dette er ikke deterministisk ettersom det avhenger av timing, andre programmer som kjører, operativsystem, implementasjon, prosessor, ram, annen hardware, og statsbudsjettet til Hellas.

Lenke til kommentar

Jeg er ikke uenig der, men det er ikke et problem med mutexer, det er et systematisk problem som må løses ved å bruke flere synkroniseringsobjekter samtidig, eventuelt vente på mange objekter samtidig og eller kombinere med flere objekter.

 

Men om du sammenligner mutex med semaforer, så vil semaforen bidra til tilfeldigheter, men mutexen vil alltid være presis. Mutexen virker perfekt selv om den ser kaotisk ut på testbenken, men det er her som sagt brukeren må koordinere tingene ved å kombinere flere objekter.

Lenke til kommentar

Ett eksempel (som kanskje ikke passer til eksemplet i denne tråden) men som bare er et eksempel vil være at hovedtråden venter på mange objekter samtidig (WaitFormultipleObjects), når alle trådene er ferdig, så kan hovedtråden igjen signalisere alle trådene til å starte samtidig, for å få en noenlunde flyt i det.

Lenke til kommentar

Mutex er hva navnet sier, mutually exclusive, godtar bare en om gangen. Og hver gang du venter på den må du tilkalle API'et noe som er dårlig i seg selv, derfor foretrekker jeg critical sections med spin count, imens den spinner så slipper den å kalle api'et.

 

Mutexet er bare en simpel variabel, ett tall som øker. Mutexer kan bare være 1 og 0. Når den er 0 så er den opptatt. Semaforer kan ha høyere tall. Semaforer fungerer nesten slik som signaliseringssystemer gjør på jernbanen.

Endret av LonelyMan
Lenke til kommentar

Mutex er hva navnet sier, mutually exclusive, godtar bare en om gangen. Og hver gang du venter på den må du tilkalle API'et noe som er dårlig i seg selv, derfor foretrekker jeg critical sections med spin count, imens den spinner så slipper den å kalle api'et.

 

Mutexet er bare en simpel variabel, ett tall som øker. Mutexer kan bare være 1 og 0. Når den er 0 så er den opptatt. Semaforer kan ha høyere tall. Semaforer fungerer nesten slik som signaliseringssystemer gjør på jernbanen.

Javisst, jeg vet jo dette. Det jeg sier er at det er ifra programmets kontekst vilkårlig hvilken tråd som vil få lås på en mutex dersom mange tråder venter på at den skal frigjøres. I motsetning til en togbane, så står ikke trådene i rekke og rad og venter på hverandre. Det er mer som svarknappen på Jeopardy.
Lenke til kommentar

Trådene blir ikke kommunisert oppgaver, det er egne tråder som jobber med sine egne ting i sin egen lille verden, men da dette ofte gir veldig fine konflikter gjorde jeg så de måtte ha en mutex for å få tilgang til ett objekt som er sentralt for hele applikasjonen.

 

Problemet oppstår ved at en tråd har veldig intensive oppgaver (tenk sjekking av &--#62;1000 sockets med krav om lav responstid til hver). Det gikk jo ikke at den holder på mutexen hele tiden så jeg gjorde så den slipper den etter en viss tid (kalkulert basert på en mengde variabler som klienter, tid per klient, krav om responstid etc). Og så re-requester den mutexen. Problemet er at dette går altfor fort, og man har ikke tid til å legge inn en pause heller da jeg ikke har råd å tape hastighet

 

Håper det var noe oppklarende. 40 i feber i dag så ble ikke mer utfyllende i dag desverre :)

 

Om jeg leser deg riktig så har du et globalt objekt som brukes av alle trådene, samt at de fleste av trådene dine er uavhengige tråder med unntak av dette globale objektet du snakker om.

 

Da anbefaler jeg at du kvitter deg med mutex objektet og legger inn en critical section. I de uavhengige trådene kan du bruke TryEnterCriticalSection, da vil den forsøke å gå inn i critical section hvis den ikke allerede er opptatt, så slipper du trege API calls om den er opptatt, hvis den er opptatt så gjør du en annen jobb som tråden må gjøre i mellomtiden, og hvis den er ledig så gjør du det du skal med det globale objektet, på den måten unngår du sløsing med cpu cycles, du gjør ett eller annet mens objektet er opptatt.

 

Men skal jeg være ærlig så tror jeg rett og slett hele programmet ditt bare er sydd sammen på feil måte, jeg er sikker på at hvis du tenker deg om så klarer du å kvitte deg med hele behovet for synkronisering.

 

I tillegg som det ble sagt tidligere, så er det nesten helt fette umulig å si hva du skal gjøre om ikke du klart, tydelig og spesifikt forklarer hva det er trådene dine gjør for noe og hva slags data de behandler og hvilke avhengigheter de har.

Endret av LonelyMan
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å
×
×
  • Opprett ny...