Ett race condition , även en tävling [ 1 ] , är ett designfel i ett flertrådigt system eller applikation, där driften av systemet eller applikationen beror på i vilken ordning delar av koden exekveras. Felet har fått sitt namn från ett liknande konstruktionsfel i elektroniska kretsar (se signalracing ).
Termen race condition syftar på ingenjörsjargong och är resultatet av en slarvig bokstavlig översättning av den engelska motsvarigheten. I en mer rigorös akademisk miljö är det vanligt att använda termen samtidighetsosäkerhet .
Ett tävlingstillstånd är ett "flytande" fel ( heisenbug ), som dyker upp vid slumpmässiga tidpunkter och "försvinner" när du försöker lokalisera det.
På grund av okontrollerad åtkomst till delat minne kan ett racetillstånd leda till helt andra fel som kan uppstå vid oförutsägbara tidpunkter, och ett försök att replikera felet i felsökningssyfte med liknande driftsförhållanden kan misslyckas.
De huvudsakliga konsekvenserna kan vara:
Strålbehandlingsmaskinen Therac -25 var den första medicinska enheten i USA som enbart förlitade sig på programvara för säkerhet . Den här enheten fungerade i tre lägen:
Dessa tre lägen ställdes in av en roterande skiva, i vilken det fanns ett hål med avböjande magneter för elektronisk terapi, och ett mål med en diffusor för röntgen. På grund av ett kapplöpningsförhållande mellan styrprogrammet och tangentbordsmotorn hände det ibland att i röntgenterapiläget var skivan i "Electron therapy"-läget och patienten bestrålades direkt med en 25 MeV elektronstråle, vilket ledde till överexponering. Samtidigt visade sensorerna "Noll dos", så att operatören kunde upprepa proceduren, vilket förvärrade situationen. Som ett resultat dog minst två patienter.
En del av koden togs från Therac-6 och Therac-20. Samtidigt hade Therac-6 ingen röntgenbehandling, och Therac-20 hade säkerhetsåtgärder för hårdvara som förhindrade strålningen från att slås på när disken var i fel position.
Tänk på ett kodexempel (i Java ).
flyktig int x ; // Tråd 1: while ( ! stop ) { x ++ ; … } // Tråd 2: while ( ! stop ) { if ( x % 2 == 0 ) System . ut . println ( "x=" + x ); … }Låt x=0. Anta att programmet körs i följande ordning:
Det enklaste sättet att lösa detta är att kopiera variabeln x till en lokal variabel. Här är den korrigerade koden:
// Tråd 2: while ( ! stop ) { int cached_x = x ; if ( cachad_x % 2 == 0 ) System . ut . println ( "x=" + cachad_x ); … }Naturligtvis fungerar denna metod endast när det bara finns en variabel och kopiering görs i en maskininstruktion.
En mer komplex och "dyrare", men också mer universell lösningsmetod är trådsynkronisering , nämligen:
int x ; // Tråd 1: while ( ! stop ) { synchronized ( someObject ) { x ++ ; } … } // Tråd 2: while ( ! stop ) { synchronized ( someObject ) { if ( x % 2 == 0 ) System . ut . println ( "x=" + x ); } … }Här händer innan semantik inte kräver nyckelordet volatile.
Anta att det finns två variabler (och nyckelordet volatilehar ingen effekt), och den andra tråden System.out.printlnhar mer komplex bearbetning istället. I det här fallet är båda metoderna otillfredsställande: den första, eftersom en variabel kan ändras medan den andra kopieras; det andra beror på att för mycket kod är synkroniserad.
Dessa metoder kan kombineras genom att kopiera "farliga" variabler i ett synkroniserat block. Å ena sidan kommer detta att ta bort begränsningen för en maskininstruktion, å andra sidan låter det dig bli av med för stora synkroniseringsblock.
flyktig int x1 , x2 ; // Tråd 1: while ( ! stop ) { synchronized ( someObject ) { x1 ++ ; x2 ++ ; } … } // Tråd 2: while ( ! stop ) { int cached_x1 , cached_x2 ; synchronized ( someObject ) { cached_x1 = x1 ; cachad_x2 = x2 ; } if (( cachad_x1 + cachad_x2 ) % 100 == 0 ) DoSomethingComplicated ( cachad_x1 , cachad_x2 ); … }Det finns inga uppenbara sätt att upptäcka och fixa tävlingsförhållanden. Det bästa sättet att bli av med raser är att korrekt designa ett multitasking-system.
Det finns en klass av buggar (och typer av attacker som utnyttjar dem) som tillåter ett oprivilegierat program att påverka driften av andra program genom möjligheten att ändra offentliga resurser (vanligtvis temporära filer ; filen är tillgänglig för skrivning av hela eller delar av användare av systemet på grund av en programmerares misstag.
Det attackerande programmet kan förstöra innehållet i filen, få offerprogrammet att krascha, eller, genom att ändra data, tvinga programmet att utföra någon åtgärd på nivån av dess privilegier.
Det är av denna anledning som programvara med allvarliga säkerhetskrav, såsom webbläsaren , använder slumptal av kryptografisk kvalitet för att namnge temporära filer.