En villkorsvariabel är en synkroniseringsprimitiv som blockerar en eller flera trådar tills en signal tas emot från en annan tråd om uppfyllandet av något villkor eller tills den maximala timeoutperioden har förflutit. Tillståndsvariabler används i samband med en associerad mutex och är en funktion för vissa typer av monitorer .
Begreppsmässigt är en villkorsvariabel en kö av trådar associerade med ett delat dataobjekt som väntar på att något villkor ska införas för datatillståndet. Således är varje villkorsvariabel associerad med en sats . När en tråd väntar på en villkorsvariabel anses den inte äga data, och en annan tråd kan modifiera det delade objektet och signalera de väntande trådarna om påståendet lyckas .
Det här exemplet illustrerar användningen av villkorsvariabler för att synkronisera producent- och konsumenttrådar. Producenttråden, som gradvis ökar värdet på den delade variabeln, signalerar till tråden som väntar på villkorsvariabeln att villkoret för det maximala värdet överskrids är uppfyllt. En väntande konsumenttråd, som kontrollerar värdet på en delad variabel, blockerar om det maximala villkoret inte är uppfyllt. När det signaleras att påståendet är sant, "konsumerar" tråden den delade resursen, vilket minskar värdet på den delade variabeln så att den inte faller under det tillåtna minimum.
I POSIX Threads- biblioteket för C är funktioner och datastrukturer med prefixet pthread_cond ansvariga för att använda villkorsvariabler.
Källkod i C med POSIX-trådar #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #define STORAGE_MIN 10 #define STORAGE_MAX 20 /* Delad resurs */ int lagring = STORAGE_MIN ; pthread_mutex_t mutex ; pthread_cond_t condition ; /* Konsumentrådsfunktion */ void * konsument ( void * args ) { sätter ( "[CONSUMER] tråden har startat" ); int to Consume = 0 ; medan ( 1 ) { pthread_mutex_lock ( & mutex ); /* Om värdet på den delade variabeln är mindre än maxvärdet, * går tråden in i tillståndet att vänta på en signal om att * maxvärdet har uppnåtts */ medan ( lagring < STORAGE_MAX ) { pthread_cond_wait ( & condition , & mutex ); } toConsume = lagring - STORAGE_MIN ; printf ( "[CONSUMER] lagring är maximal, förbrukar %d \n " , \ toConsume ); /* "Förbrukning" av den tillåtna volymen från värdet av den delade * variabeln */ lagring -= toConsume ; printf ( "[CONSUMER] lagring = %d \n " , lagring ); pthread_mutex_unlock ( & mutex ); } returnera NULL ; } /* Producent tråd funktion */ void * producent ( void * args ) { sätter ( "[PRODUCENT] tråden har startat" ); medan ( 1 ) { usleep ( 200000 ); pthread_mutex_lock ( & mutex ); /* Producer ökar hela tiden värdet på den delade variabeln */ ++ lagring ; printf ( "[PRODUCENT] lagring = %d \n " , lagring ); /* Om värdet på den delade variabeln når eller överstiger * maxvärdet meddelas konsumenttråden */ if ( lagring >= STORAGE_MAX ) { sätter ( "[PRODUCENT] lagringsmaximum" ); pthread_cond_signal ( & condition ); } pthread_mutex_unlock ( & mutex ); } returnera NULL ; } int main ( int argc , char * argv []) { int res = 0 ; pthread_t thProducer , thConsumer ; pthread_mutex_init ( & mutex , NULL ); pthread_cond_init ( & condition , NULL ); res = pthread_create ( & thProducer , NULL , producer , NULL ); om ( res != 0 ) { perror ( "pthread_create" ); avsluta ( EXIT_FAILURE ); } res = pthread_create ( & thConsumer , NULL , konsument , NULL ); om ( res != 0 ) { perror ( "pthread_create" ); avsluta ( EXIT_FAILURE ); } pthread_join ( thProducer , NULL ); pthread_join ( thConsumer , NULL ); returnera EXIT_SUCCESS ; }C++11-standarden lade till stöd för multithreading till språket. Arbete med villkorsvariabler tillhandahålls av medel som deklareras i rubrikfilen condition_variable
Källtext i C++ (C++11) #include <cstdlib> #include <iostream> #inkludera <tråd> #inkludera <mutex> #inkludera <villkorsvariabel> #inkludera <chrono> #define STORAGE_MIN 10 #define STORAGE_MAX 20 int lagring = STORAGE_MIN ; std :: mutex globalMutex ; std :: condition_variable condition ; /* Konsumentrådsfunktion */ ogiltig konsument () { std :: cout << "[CONSUMER] tråd startad" << std :: endl ; int to Consume = 0 ; medan ( sant ) { std :: unikt_lås < std :: mutex > lås ( globalMutex ); /* Om värdet på den delade variabeln är mindre än maxvärdet, * går tråden in i tillståndet att vänta på en signal om att * maxvärdet har uppnåtts */ if ( lagring < STORAGE_MAX ) { skick . vänta ( lås , [][]{ retur lagring >= STORAGE_MAX ;} ); // Atomically _släpper mutex_ och blockerar omedelbart tråden toConsume = storage - STORAGE_MIN ; std :: cout << "[CONSUMER] lagring är maximal, konsumerar" << toConsume << std :: endl ; } /* "Förbrukning" av den tillåtna volymen från värdet av den delade * variabeln */ lagring -= toConsume ; std :: cout << "[CONSUMER] storage = " << lagring << std :: endl ; } } /* Producent tråd funktion */ ogiltig producent () { std :: cout << "[PRODUCENT] tråd startad" << std :: endl ; medan ( sant ) { std :: denna_tråd :: sleep_for ( std :: chrono :: millisekunder ( 200 )); std :: unikt_lås < std :: mutex > lås ( globalMutex ); ++ lagring ; std :: cout << "[PRODUCER] storage = " << lagring << std :: endl ; /* Om värdet på den delade variabeln når eller överstiger * maxvärdet meddelas konsumenttråden */ if ( lagring >= STORAGE_MAX ) { std :: cout << "[PRODUCENT] lagringsmax" << std :: endl ; skick . notify_one (); } } } int main ( int argc , char * argv []) { std :: thread thProducer ( producent ); std :: tråd thConsumer ( konsument ); producenten . gå med (); konsumenten . gå med (); returnera 0 ; }cw.h
#ifndef CW_H #definiera CW_H #include <QThread> #include <QMutex> #include <QWaitCondition> #include <QDebug> #define STORAGE_MIN 10 #define STORAGE_MAX 20 extern int lagring ; extern QMutex qmt ; extern QWaitCondition skick ; klass Producent : public QThread { Q_OBJECT privat : void run () { qDebug () << "[PRODUCENT] tråd startad" ; medan ( 1 ) { QThread :: msleep ( 200 ); qmt . lås (); ++ lagring ; qDebug () << "[PRODUCER] storage = " << lagring ; /* Om värdet på den delade variabeln når eller överstiger * maxvärdet meddelas konsumenttråden */ if ( lagring >= STORAGE_MAX ) { qDebug () << "[PRODUCENT] lagringsmaximum" ; skick . wakeOne (); } qmt . låsa upp (); } } }; klass Konsument : offentlig QThread { Q_OBJECT privat : void run () { qDebug () << "[CONSUMER] tråd startad" ; int to Consume = 0 ; medan ( 1 ) { qmt . lås (); /* Om värdet på den delade variabeln är mindre än maxvärdet, * går tråden in i tillståndet att vänta på en signal om att * maxvärdet har uppnåtts */ if ( lagring < STORAGE_MAX ) { skick . vänta ( & qmt ); toConsume = lagring - STORAGE_MIN ; qDebug () << "[CONSUMER] lagringsutrymme är maximalt, konsumerar" << toConsume ; } /* "Förbrukning" av den tillåtna volymen från värdet av den delade * variabeln */ lagring -= toConsume ; qDebug () << "[CONSUMER] storage = " << lagring ; qmt . låsa upp (); } } }; #endif /* CW_H */main.cpp
#include <QCoreApplication> #inkludera "cw.h" int lagring = STORAGE_MIN ; QMutex qmt ; QWaitCondition skick ; int main ( int argc , char * argv []) { QCoreApplication app ( argc , argv ); Producent prod ; konsument nackdelar ; prod . start (); nackdelar . start (); returnera app . exec (); }I Python implementeras villkorsvariabler som instanser av Conditionmodulklassen threading. Följande exempel använder samma villkorsvariabel i producent- och konsumenttrådarna med hjälp av syntaxen för kontexthanteraren [1]
# En konsumenttråd med cond_var : # i kontexten av ett cond_var condition while not an_item_is_available (): # medan artikeln inte är tillgänglig cond_var . vänta () # vänta get_an_item () # hämta objektet # Producenttråd med cond_var : # i sammanhanget av ett cond_var-villkor make_an_item_available () # producera ett cond_var- objekt . meddela () # meddela konsumenterI Ada- språket finns det inget behov av att använda villkorsvariabler. Det är möjligt att använda skyddade datatyper för att organisera uppgiftsblockerande monitorer.
Ada '95 källkod med Ada.Text_IO ; procedur Main är uppgift Producent ; -- Uppgift om producentuppgiftsdeklaration Konsument ; -- Konsumentuppgiftsdeklaration typ Storage_T är intervallet 10 .. 20 ; -- intervalltyp för andel -- övervaka (skyddat objekt) som delas av producent och konsumentskyddad typ Lagring är entry Put ; -- operation " producera " resursenhetspost Get ; -- operation för att "konsumera" den tillåtna mängden resursinmatning Value ( val : out Storage_T ) ; -- variabel värde accessor privat -- dold variabel med minsta initiala värde från intervall av typen StorageData : Storage_T := Storage_T ' First ; slut Lagring ; -- övervaka implementering Lagringsskyddad kropp Lagring är inträde Lägg när StorageData < Storage_T ' Last is start StorageData : = StorageData + 1 ; om StorageData >= Storage_T ' Last then Ada . text_IO . Put_Line ( "[PRODUCER] lagringsmaximum" ); sluta om ; slut ; entry Get when StorageData >= Storage_T ' Last is To_Consume : Storage_T ; begin To_Consume := StorageData - Storage_T ' First ; StorageData := StorageData - To_Consume ; Ada . text_IO . Put_Line ( "[CONSUMER] konsumerar" ); slut Få ; entry Value ( val : out Storage_T ) när sant är start val := StorageData ; slut ; slut Lagring ; -- övervaka instans Storage Storage1 : Storage ; -- implementering av uppgiftsorganet för producentuppgiften Producenten är v : Storage_T ; börja Ada . text_IO . Put_Line ( "[PRODUCENT] Uppgift startat" ); loopfördröjning 0,2 ; _ Förvaring 1 . sätta ; Förvaring 1 . Värde ( v ); Ada . text_IO . put ( "[PRODUCENT]" ); Ada . text_IO . Put_Line ( v ' Img ); end -loop ; slutproducent ; _ -- Konsument uppgift genomförande uppgift organ Konsument börjar Ada . text_IO . Put_Line ( "[KUNDEN] Uppgiften startade" ); loopStorage1 . _ få ; end -loop ; slutkonsument ; _ börja null ; endMain ; _