Qt-dokumentasjon.

Qt-dokumentasjon.

Hva er trader?

Trader handler om a gjore ting parallelt, akkurat som prosesser. Sa hvordan er trader forskjellig fra prosesser? Mens du lager beregninger pa et regneark, kan det ogsa v re en mediespiller som kjorer pa samme skrivebord som spiller din favoritt sang. Her er et eksempel pa to prosesser som fungerer parallelt: en kjorer regnearkprogrammet; en kjorer en mediespiller. Multitasking er et godt kjent uttrykk for dette. En n rmere titt pa mediespilleren avslorer at det igjen skjer ting parallelt i en enkelt prosess. Mens mediespilleren sender musikk til lyddriveren, blir brukergrensesnittet med alle sine klokker og floyter kontinuerlig oppdatert. Dette er hva trader er for samtidighet innenfor en enkelt prosess.

Sa hvordan implementeres samtidighet? Parallelt arbeid pa single core CPUer er en illusjon som i likhet med illusjonen av bevegelige bilder i kino. For prosesser blir illusjonen produsert ved a forstyrre prosessorens arbeid pa en prosess etter kort tid. Deretter gar prosessoren videre til neste prosess. For a bytte mellom prosesser lagres den aktuelle programtelleren og neste prosessorens programteller er lastet inn. Dette er ikke tilstrekkelig fordi det samme ma gjores med registre og visse arkitekturer og OS-spesifikke data.

Akkurat som en CPU kan drive to eller flere prosesser, er det ogsa mulig a la CPUen kjore pa to forskjellige kodesegmenter av en enkelt prosess. Nar en prosess starter, utforer den alltid ett kodesegment, og prosessen sies derfor a ha en trad. Programmet kan imidlertid bestemme seg for a starte en andre trad. Deretter behandles to forskjellige kodesekvenser samtidig i en prosess. Sammenlikning oppnas pa enkle kjerne-CPUer ved a lagre programteller og -registre flere ganger og laster deretter neste trads programteller og -registre. Ingen samarbeid fra programmet er nodvendig for a sykle mellom de aktive tradene. En trad kan v re i hvilken som helst tilstand nar bryteren til neste trad oppstar.

Den nav rende trenden i CPU-design er a ha flere kjerner. En typisk single-threaded applikasjon kan bare benytte en kjerne. Men et program med flere trader kan tilordnes flere kjerner, slik at ting skjer i en virkelig samtidig mate. Som et resultat kan distribusjon av arbeid til mer enn en trad gjore et program kjort mye raskere pa multicore-CPUer fordi flere kjerner kan brukes.

GUI-trad og arbeidstrad.

Som nevnt har hvert program en trad nar den startes. Denne traden kalles «hovedtraden» (ogsa kjent som «GUI-traden» i Qt-applikasjoner). Qt GUI ma kjore i denne traden. Alle widgets og flere relaterte klasser, for eksempel QPixmap, fungerer ikke i sekund re trader. En sekund r traden blir ofte referert til som en «arbeidstrad» fordi den brukes til a avlaste prosessarbeid fra hovedtraden.

Samtidig tilgang til data.

Hver trad har sin egen stabel, som betyr at hver trad har sin egen anropshistorie og lokale variabler. Til forskjell fra prosesser deler trader samme adresserom. Folgende diagram viser hvordan byggeblokkene av tradene er plassert i minnet. Programteller og register over inaktive trader holdes vanligvis i kjerneplass. Det er en felles kopi av koden og en egen stabel for hver trad.

Hvis to trader har en peker pa det samme objektet, er det mulig at begge trader far tilgang til objektet samtidig, og dette kan potensielt odelegge objektets integritet. Det er lett a forestille seg de mange tingene som kan ga galt nar to metoder for det samme objektet utfores samtidig.

Noen ganger er det nodvendig a fa tilgang til ett objekt fra forskjellige trader; for eksempel nar objekter som lever i forskjellige trader, trenger a kommunisere. Siden trader bruker samme adresserom, er det enklere og raskere for trader a utveksle data enn det er for prosesser. Data trenger ikke a bli serialisert og kopiert. Passing pointers er mulig, men det ma v re en streng koordinering av hvilken trad som berorer hvilken gjenstand. Samtidig utforelse av operasjoner pa ett objekt ma forhindres. Det er flere mater a oppna dette pa, og noen av dem er beskrevet nedenfor.

Sa hva kan gjores trygt? Alle objekter som er opprettet i en trad, kan brukes trygt i denne traden, forutsatt at andre trader ikke har referanser til dem og objekter ikke har implisitt kopling med andre trader. Slik implisitt kopling kan skje nar data deles mellom forekomster som med statiske medlemmer, singletoner eller globale data. Bli kjent med konseptet om tradsikker og reentrant klasser og funksjoner.

Bruker trader.

Det er i utgangspunktet to brukstilfeller for trader:

Gjor behandlingen raskere ved a bruke multicore-prosessorer. Hold GUI-traden eller andre kritiske trader som reagerer ved a laste ut langvarig behandling eller blokkere anrop til andre trader.

Nar skal du bruke alternativer til trader.

Utviklere ma v re veldig forsiktig med trader. Det er enkelt a starte andre trader, men sv rt vanskelig a sikre at alle delte data forblir konsistente. Problemer er ofte vanskelig a finne, fordi de kanskje bare vises en gang til, eller bare pa bestemte maskinvarekonfigurasjoner. For du oppretter trader for a lose visse problemer, bor mulige alternativer vurderes.

Generelt anbefales det a bare bruke sikre og testede baner og unnga a innfore ad hoc-tradekonsepter. QtConcurrent gir et enkelt grensesnitt for a distribuere arbeid til alle prosessorens kjerner. Tradekoden er helt skjult i QtConcurrent-rammeverket, slik at du ikke trenger a ta vare pa detaljene. Imidlertid kan QtConcurrent ikke brukes nar kommunikasjon med traden er nodvendig, og den skal ikke brukes til a handtere blokkering.

Hvilken Qt-tradteknologi bor du bruke?

Noen ganger vil du gjore mer enn bare a kjore en metode i sammenheng med en annen trad. Du vil kanskje ha et objekt som lever i en annen trad som gir en tjeneste til GUI-traden. Kanskje du vil ha en annen trad for a holde seg i live for alltid a koble maskinvareportene og sende et signal til GUI-traden nar noe som er bemerkelsesverdig, har skjedd. Qt gir forskjellige losninger for a utvikle gjengede applikasjoner. Den riktige losningen er avhengig av formalet med den nye traden, sa vel som pa tradenes levetid.

Qt trad grunnleggende.

QThread er en veldig praktisk kryssplattformabstrakt av innfodte plattformtrader. A starte en trad er veldig enkel. La oss se pa et kort stykke kode som genererer en annen trad som sier hei i den traden og avslutter deretter.

Vi utlede en klasse fra QThread og reimplement run () metoden.

Kjoremetoden inneholder koden som skal kjores i en egen trad. I dette eksemplet vil en melding som inneholder trad-IDen bli skrevet ut. QThread :: start () vil kalle metoden i en annen trad.

For a starte traden, ma vart tradobjekt v re instantiated. Metoden start () lager en ny trad og kaller reimplemented run () -metoden i denne nye traden. Rett etter at start () kalles, gar to programteller gjennom programkoden. Hovedfunksjonen starter med bare GUI-traden som kjorer, og den bor avslutte med bare GUI-traden som kjorer. Avslutte programmet nar en annen trad fortsatt er opptatt, er en programmeringsfeil, og derfor kalles ventetiden som blokkerer samtaletraden til fremgangsmaten run () har fullfort.

Dette er resultatet av a kjore koden:

QObject og trader.

Som nevnt ovenfor ma utviklere alltid v re forsiktige nar man ringer objekter ‘metoder fra andre trader. Tradaffinitet endrer ikke denne situasjonen. Qt-dokumentasjon markerer flere metoder som tradsikker. postEvent () er et bemerkelsesverdig eksempel. En tradsikker metode kan bli kalt fra forskjellige trader samtidig.

I tilfeller der det vanligvis ikke foreligger samtidig tilgang til metoder, kan det v re a jobbe tusenvis av ganger uten a bruke tradlose sikkerhetsmetoder for objekter i andre trader for en samtidig tilgang oppstar, noe som forarsaker uventet oppforsel. Skrivingstestkoden sikrer ikke helt korrekt trad, men det er fortsatt viktig. Pa Linux kan Valgrind og Helgrind bidra til a oppdage traderfeil.

Bruke en Mutex for a beskytte integriteten av data.

En mutex er et objekt som har lasemetoder () og laser opp () og husker om det allerede er last. En mutex er designet for a bli kalt fra flere trader. las () returnerer umiddelbart hvis mutex ikke er last. Det neste anropet fra en annen trad finner mutexen i last tilstand, og deretter lases () vil traden trekke til den andre traden lases opp (). Denne funksjonaliteten kan sorge for at en kodeseksjon utfores av bare en trad om gangen.

Folgende linje skisserer hvordan en mutex kan brukes til a gjore en metode tradsikker:

Hva skjer hvis en trad ikke laser opp en mutex? Resultatet kan v re en frossen applikasjon. I eksemplet ovenfor kan et unntak kastes og mutex.unlock () vil aldri bli nadd. For a forhindre problemer som dette, bor QMutexLocker brukes.

Dette ser lett ut, men mutexes introduserer en ny klasse av problemer: deadlocks. En dodlas skjer nar en trad venter pa at en mutex blir ulast, men mutexen forblir last fordi eiersjangen venter pa den forste traden for a lase den opp. Resultatet er en frossen applikasjon. Mutexes kan brukes til a gjore en metode trad sikker. De fleste Qt-metodene er ikke tradsikre fordi det alltid er en ytelsesstraff ved bruk av mutexes.

Det er ikke alltid mulig a lase og lase opp en mutex i en metode. Noen ganger trenger behovet for a lase spenner over flere samtaler. For eksempel krever endring av en container med en iterator en rekkefolge av flere samtaler som ikke skal avbrytes av andre trader. I et slikt scenario kan lasing oppnas med en mutex som holdes utenfor objektet som skal manipuleres. Med ekstern mutex kan lengden pa lasingen justeres etter behovene til operasjonen. En ulempe er at ekstern mutexes lases, men ikke handheve det fordi brukere av objektet kan glemme a bruke det.

Bruke Event Loop for a forhindre dataforstyrrelse.

Eventlokkene til Qt er et sv rt verdifullt verktoy for inter-thread-kommunikasjon. Hver trad kan ha sin egen hendelseslokke. En trygg mate a ringe et spor pa i en annen trad er ved a plassere det anropet i en annen trads hendelseslokke. Dette sikrer at malobjektet fullforer metoden som kjorer for en annen metode er startet.

Sa hvordan er det mulig a sette en metodeinnkalling i en hendelseslokke? Qt har to mater a gjore dette pa. En mate er via koen signal-slotsforbindelser; Den andre maten er a legge inn en hendelse med QCoreApplication :: postEvent (). En kolesignal-slotsforbindelse er en signalsporforbindelse som utfores asynkront. Den interne implementeringen er basert pa utsendte hendelser. Argumentene til signalet settes inn i hendelseslokken og signalmetoden returnerer umiddelbart.

Den tilkoblede sporet vil bli utfort pa et tidspunkt som avhenger av hva som skjer i hendelseslokken.

Kommunikasjon via hendelsessloylen eliminerer problemlosningen vi moter nar du bruker mutexes. Det er derfor vi anbefaler a bruke hendelseslokken i stedet for a lase et objekt ved hjelp av en mutex.

A handtere asynkron gjennomforing.

En mate a fa tak i en arbeidstrads trad er ved a vente pa at traden skal avslutte. I mange tilfeller er imidlertid en blokkering venter ikke akseptabel. Alternativet til en blokkering venter er asynkrone resultatleveranser med enten postede hendelser eller kossignaler og spor. Dette genererer en viss overhead fordi et operasjonsresultat ikke vises pa neste kilde linje, men i et spor som er plassert et annet sted i kildefilen. Qt-utviklere er vant til a jobbe med denne typen asynkronadferd fordi det er mye lik den typen hendelsesdrevet programmering som brukes i GUI-applikasjoner.

Denne oppl ringen kommer med eksempler pa Qts tre grunnleggende mater a jobbe med trader. To eksempler viser hvordan man kommuniserer med en lopende trad og hvordan et QObject kan plasseres i en annen trad, og gir service til hovedtraden.

Folgende eksempler kan alle kompileres og kjores uavhengig. Kilden finner du i eksemplet katalogen: eksempler / oppl ring / trader /

Eksempel 1: Bruk av tradspolen.

A lage og odelegge trader ofte kan v re dyrt. For a unnga kostnaden for tradenes opprettelse, kan et tradbasseng brukes. Et tradbad er et sted hvor trader kan parkeres og hentes. Vi kan skrive det samme «hei trad» -programmet som ovenfor ved hjelp av det globale tradbassenget. Vi utlede en klasse fra QRunnable. Koden vi onsker a kjore i en annen trad ma plasseres i reimplemented QRunnable :: run () -metoden.

Vi ordner Arbeid i hoved (), finn det globale tradspillet og bruk QThreadPool :: start () -metoden. Na trader bassenget var arbeider i en annen trad. Bruk av tradbassenget har en ytelsesfordel fordi trader ikke odelegges etter at de er ferdige. De holdes i et basseng og venter pa a bli brukt igjen senere.

Eksempel 2: Bruke QtConcurrent.

Vi skriver en global funksjon hallo () for a gjennomfore arbeidet. QtConcurrent :: run () brukes til a kjore funksjonen i en annen trad. Resultatet er en QFuture. QFuture gir en metode som kalles waitForFinished (), som blokkerer til beregningen er fullfort. Den virkelige kraften til QtConcurrent blir synlig nar data kan gjores tilgjengelig i en container. QtConcurrent gir flere funksjoner som kan behandle spesifiserte data pa alle tilgjengelige kjerner samtidig. Bruken av QtConcurrent ligner meget pa a bruke en STL-algoritme til en STL-beholder. QtConcurrent Map er et veldig kort og klart eksempel pa hvordan en beholder med bilder kan skaleres pa alle tilgjengelige kjerner. Bildeskalingseksemplet bruker blokkeringsvarianter av funksjonene som brukes. For hver blokkeringsfunksjon er det ogsa en ikke-blokkerende, asynkron motpart. A fa resultater asynkront er implementert med QFuture og QFutureWatcher.

Eksempel 3: Klokke.

Vi onsker a produsere en klokkeapplikasjon. Soknaden har en GUI og en arbeiderrad. Arbeidsgruppen sjekker hver 10 millisekunder nar den er. Hvis formatert tid er endret, sendes resultatet til GUI-traden der den vises.

Selvfolgelig er dette en altfor komplisert mate a designe en klokke pa, og faktisk er det ikke nodvendig med en egen trad. Vi ville v re bedre a plassere timeren i hovedtraden fordi beregningen som er gjort i tidssporingen er sv rt kortvarig. Dette eksemplet er rent for instruksjonsbruk og viser hvordan man kommuniserer fra en arbeidstrad til en GUI-trad. Merk at kommunikasjon i denne retningen er enkel. Vi trenger bare a legge til et signal til QThread og gjore en signal / sloyfeforbindelse i ko til hovedtraden. Kommunikasjon fra GUI til arbeidstrad er vist i neste eksempel.

Vi har koblet klokken med etiketten. Tilkoblingen ma v re en kossignal-spor-tilkobling fordi vi onsker a sette anropet i hendelseslokken.

Vi har avledet en klasse fra QThread og erkl rte signalet sendTime ().

Den vanskeligste delen av dette eksemplet er at timeren er koblet til sporet via en direkte forbindelse. En standardforbindelse vil produsere en kossignal-spor-tilkobling fordi de tilkoblede objektene lever i forskjellige trader; husk at QThread ikke lever i traden det skaper.

Likevel er det trygt a fa tilgang til ClockThread :: timerHit () fra arbeiderens trad fordi ClockThread :: timerHit () er privat og bare berorer lokale variabler og et privat medlem som ikke berores av offentlige metoder. QDateTime :: currentDateTime () er ikke merket som tradsikker i Qt-dokumentasjon, men vi kan komme seg unna med a bruke det i dette lille eksempelet fordi vi vet at QDateTime :: currentDateTime () statisk metode ikke brukes i noen andre trader.

Eksempel 4: En permanent trad.

Dette eksemplet viser hvordan det er mulig a fa en QObject i en arbeidstrad som aksepterer foresporsler fra GUI-traden, polling ved hjelp av en timer og rapporterer kontinuerlig resultater tilbake til GUI-traden. Det faktiske arbeidet, inkludert avstemningen, ma gjennomfores i en klasse avledet fra QObject. Vi har kalt denne klassen WorkerObject i koden vist nedenfor. Den tradspesifikke koden er skjult i en klasse som kalles Trad, avledet fra QThread. Trad har to ekstra offentlige medlemmer. Medlemmet launchWorker () tar arbeiderobjektet og flytter det til en annen trad med en startet hendelseslokke. Samtalen blokerer i et veldig kort oyeblikk til tradenes opprettelsesoperasjon er fullfort, slik at arbeiderobjektet kan brukes igjen pa neste linje. Thread-klassens kode er kort, men litt involvert, sa vi viser bare hvordan du skal bruke klassen.

QMetaObject :: invokeMethod () kaller et spor via hendelseslokken. Arbeidsobjektets metoder bor ikke kalles direkte etter at objektet er flyttet til en annen trad. Vi lar arbeiderens trad gjore noe arbeid og avstemning, og bruk en timer for a stenge programmet ned etter 3 sekunder. A stenge arbeideren ned trenger litt forsiktighet. Vi kaller Thread :: stop () for a avslutte hendelseslokken. Vi venter pa a avslutte traden, og etter at dette har skjedd, sletter vi arbeideren.

Graver dypere.

Threading er et sv rt komplisert emne. Qt tilbyr flere klasser for trader enn vi har presentert i denne oppl ringen. Folgende materialer kan hjelpe deg med a ga n rmere inn i emnet:

Gode videooppl ringer om trader med Qt finnes i materialet fra treningsdagen pa Qt Developer Days 2009. Tradstotten i Qt-dokumentet er et godt utgangspunkt i referansedokumentasjonen. Qt kommer med flere flere eksempler for QThread og QtConcurrent. Flere gode boker beskriver hvordan man arbeider med Qt-trader. Den mest omfattende dekningen finnes i Avansert Qt Programmering av Mark Summerfield, Prentice Hall – omtrent 70 av 500 sider dekker QThread og QtConcurrent.