En betingelsesvariabel er en synkroniseringsprimitiv , der blokerer en eller flere tråde , indtil der modtages et signal fra en anden tråd om opfyldelsen af en betingelse, eller indtil den maksimale timeout-periode er udløbet. Tilstandsvariabler bruges sammen med en tilknyttet mutex og er en funktion af nogle slags monitorer .
Konceptuelt er en betingelsesvariabel en kø af tråde, der er knyttet til et delt dataobjekt, som venter på, at en betingelse pålægges datatilstanden. Hver betingelsesvariabel er således forbundet med en erklæring . Når en tråd venter på en betingelsesvariabel, anses den ikke for at eje dataene, og en anden tråd kan ændre det delte objekt og signalere de ventende tråde, hvis påstanden lykkes .
Dette eksempel illustrerer brugen af betingelsesvariable til at synkronisere producent- og forbrugertråde. Producerende tråd, der gradvist øger værdien af den delte variabel, signalerer til tråden, der venter på betingelsesvariablen, at den maksimale værdi overskredet betingelse er opfyldt. En ventende forbrugertråd, der kontrollerer værdien af en delt variabel, blokerer, hvis den maksimale betingelse ikke er opfyldt. Når det signaleres, at påstanden er sand, "forbruger" tråden den delte ressource, og reducerer værdien af den delte variabel, så den ikke falder under det tilladte minimum.
I POSIX Threads -biblioteket for C er funktioner og datastrukturer med præfiks med pthread_cond ansvarlige for at bruge betingelsesvariabler.
Kildekode i C ved hjælp af POSIX-tråde #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #define STORAGE_MIN 10 #define STORAGE_MAX 20 /* Delt ressource */ int lager = STORAGE_MIN ; pthread_mutex_t mutex ; pthread_cond_t tilstand ; /* Forbrugertrådsfunktion */ void * forbruger ( void * args ) { puts ( "[CONSUMER] tråd startet" ); int til at forbruge = 0 ; mens ( 1 ) { pthread_mutex_lock ( & mutex ); /* Hvis værdien af den delte variabel er mindre end maksimum, * så går tråden ind i tilstanden, hvor den venter på et signal om, at * maksimum er nået */ mens ( lagerplads < STORAGE_MAX ) { pthread_cond_wait ( & condition , & mutex ); } toConsume = lagerplads - STORAGE_MIN ; printf ( "[CONSUMER] lagerplads er maksimal, forbruger %d \n " , \ toConsume ); /* "Forbrug" af det tilladte volumen fra værdien af den delte * variabel */ storage -= toConsume ; printf ( "[CONSUMER] lager = %d \n " , lager ); pthread_mutex_unlock ( & mutex ); } returner NULL ; } /* Producent tråd funktion */ void * producent ( void * args ) { puts ( "[PRODUCER] tråd startet" ); mens ( 1 ) { usleep ( 200000 ); pthread_mutex_lock ( & mutex ); /* Producer øger konstant værdien af den delte variabel */ ++ opbevaring ; printf ( "[PRODUCER] lager = %d \n " , lager ); /* Hvis værdien af den delte variabel når eller overstiger * maksimum, får forbrugertråden besked */ if ( lager >= STORAGE_MAX ) { puts ( "[PRODUCER] lagermaksimum" ); pthread_cond_signal ( & betingelse ); } pthread_mutex_unlock ( & mutex ); } returner NULL ; } int main ( int argc , char * argv []) { int res = 0 ; pthread_t thProducer , thConsumer ; pthread_mutex_init ( & mutex , NULL ); pthread_cond_init ( & betingelse , NULL ); res = pthread_create ( & thProducer , NULL , producer , NULL ); hvis ( res != 0 ) { perror ( "pthread_create" ); exit ( EXIT_FAILURE ); } res = pthread_create ( & thConsumer , NULL , forbruger , NULL ); hvis ( res != 0 ) { perror ( "pthread_create" ); exit ( EXIT_FAILURE ); } pthread_join ( thProducer , NULL ); pthread_join ( thConsumer , NULL ); returner EXIT_SUCCESS ; }C++11-standarden tilføjede understøttelse af multithreading til sproget. Arbejde med betingede variabler leveres af midler, der er erklæret i header-filen condition_variable
Kildetekst i C++ (C++11) #include <cstdlib> #include <iostream> #inkluder <tråd> #include <mutex> #include <condition_variable> #include <chrono> #define STORAGE_MIN 10 #define STORAGE_MAX 20 int lager = STORAGE_MIN ; std :: mutex globalMutex ; std :: condition_variable condition ; /* Forbrugertrådsfunktion */ ugyldig forbruger () { std :: cout << "[CONSUMER] tråd startet" << std :: endl ; int til at forbruge = 0 ; mens ( sandt ) { std :: unik_lås < std :: mutex > lås ( globalMutex ); /* Hvis værdien af den delte variabel er mindre end maksimum, * så går tråden ind i tilstanden, hvor den venter på et signal om, at * maksimum er nået */ if ( lagerplads < STORAGE_MAX ) { tilstand . vent ( lås , [][]{ retur lagerplads >= STORAGE_MAX ;} ); // Atomically _frigiver mutex_ og blokerer straks tråden toConsume = storage - STORAGE_MIN ; std :: cout << "[CONSUMER] lagerplads er maksimal, forbrugende" << toConsume << std :: endl ; } /* "Forbrug" af det tilladte volumen fra værdien af den delte * variabel */ storage -= toConsume ; std :: cout << "[CONSUMER] storage = " << lager << std :: endl ; } } /* Producent tråd funktion */ ugyldig producent () { std :: cout << "[PRODUCENT] tråd startet" << std :: endl ; mens ( sandt ) { std :: denne_tråd :: sleep_for ( std :: chrono :: millisekunder ( 200 )); std :: unik_lås < std :: mutex > lås ( globalMutex ); ++ opbevaring ; std :: cout << "[PRODUCER] storage = " << lager << std :: endl ; /* Hvis værdien af den delte variabel når eller overstiger * maksimum, får forbrugertråden besked */ if ( lager >= STORAGE_MAX ) { std :: cout << "[PRODUCER] lagermaksimum" << std :: endl ; tilstand . notify_one (); } } } int main ( int argc , char * argv []) { std :: tråd thProducer ( producent ); std :: tråd thConsumer ( forbruger ); producenten . deltage (); Forbrugeren . deltage (); returnere 0 ; }cw.h
#ifndef CW_H #define CW_H #include <QThread> #include <QMutex> #include <QWaitCondition> #include <QDebug> #define STORAGE_MIN 10 #define STORAGE_MAX 20 ekstern int lagring ; ekstern QMutex qmt ; ekstern QWaitCondition tilstand ; klasse Producent : offentlig QThread { Q_OBJECT privat : void run () { qDebug () << "[PRODUCER] tråd startet" ; mens ( 1 ) { QThread :: msleep ( 200 ); qmt . lås (); ++ opbevaring ; qDebug () << "[PRODUCER] storage = " << lager ; /* Hvis værdien af den delte variabel når eller overstiger * maksimum, får forbrugertråden besked */ if ( lager >= STORAGE_MAX ) { qDebug () << "[PRODUCER] lagermaksimum" ; tilstand . wakeOne (); } qmt . låse op (); } } }; klasse Forbruger : offentlig QThread { Q_OBJECT privat : void run () { qDebug () << "[CONSUMER] tråd startet" ; int til at forbruge = 0 ; mens ( 1 ) { qmt . lås (); /* Hvis værdien af den delte variabel er mindre end maksimum, * så går tråden ind i tilstanden, hvor den venter på et signal om, at * maksimum er nået */ if ( lagerplads < STORAGE_MAX ) { tilstand . vent ( & qmt ); toConsume = lagerplads - STORAGE_MIN ; qDebug () << "[CONSUMER] lagerplads er maksimal, forbrugende" << toConsume ; } /* "Forbrug" af det tilladte volumen fra værdien af den delte * variabel */ storage -= toConsume ; qDebug () << "[CONSUMER] storage = " << lager ; qmt . låse op (); } } }; #endif /* CW_H */main.cpp
#include <QCoreApplication> #include "cw.h" int lager = STORAGE_MIN ; QMutex qmt ; QWaitCondition tilstand ; int main ( int argc , char * argv []) { QCoreApplication app ( argc , argv ); Producent prod ; forbruger ulemper ; prod . start (); ulemper . start (); retur app . exec (); }I Python er betingelsesvariable implementeret som forekomster af Conditionmodulklassen threading. Følgende eksempel bruger den samme betingelsesvariabel i producent- og forbrugertrådene ved hjælp af kontekststyringssyntaks [1]
# En forbrugertråd med cond_var : # i konteksten af en cond_var condition mens ikke an_item_is_available (): # mens varen ikke er tilgængelig cond_var . vent () # vent hent_en_vare () # hent varen # Producenttråd med cond_var : # i sammenhæng med en cond_var-tilstand make_an_item_available () # fremstille en cond_var- vare . underrette () # underrette forbrugereI Ada -sproget er der ingen grund til at bruge betingelsesvariable. Det er muligt at bruge beskyttede datatyper til at organisere opgaveblokerende skærme.
Ada '95 kildekode med Ada.Text_IO ; procedure Main er opgave Producer ; -- producentopgaveerklæringsopgave Forbruger ; -- forbrugeropgaveerklæring type Storage_T er område 10 .. 20 ; -- områdetype til andel -- monitor (beskyttet objekt) delt af producent og forbruger beskyttet type Opbevaring er entry Put ; -- operation "producer" ressourceenhedsindtastning Hent ; -- operation til at "forbruge" den tilladte mængde af ressourceindtastning Værdi ( val : out Storage_T ) ; -- variabel værdi accessor private -- skjult variabel med minimum startværdi fra området af typen StorageData : Storage_T := Storage_T ' First ; ende Opbevaring ; -- overvåg implementering Lagerbeskyttet krop Storage er indtastning Sæt når StorageData < Storage_T ' Sidst er start StorageData : = StorageData + 1 ; hvis StorageData >= Storage_T ' Sidst så Ada . tekst_IO . Put_Line ( "[PRODUCER] lagermaksimum" ); ende hvis ; ende ; indgang Hent når StorageData >= Storage_T ' Sidst er To_Consume : Storage_T ; begin To_Consume := StorageData - Storage_T ' First ; StorageData := StorageData - To_Consume ; Ada . tekst_IO . Put_Line ( "[CONSUMER] forbrugende" ); ende Få ; entry Value ( val : out Storage_T ), når sand er start val := StorageData ; ende ; ende Opbevaring ; -- monitor instans Storage Storage1 : Storage ; -- implementering af opgaveorganet for producentopgaven Producer er v : Storage_T ; begynde Ada . tekst_IO . Put_Line ( "[PRODUCER] Opgave startet" ); sløjfeforsinkelse 0,2 ; _ Opbevaring 1 . sætte ; Opbevaring 1 . Værdi ( v ); Ada . tekst_IO . put ( "[PRODUCER]" ); Ada . tekst_IO . Put_Line ( v ' Img ); ende -løkke ; slutproducent ; _ -- forbruger opgave implementering opgave organ Forbruger er begynde Ada . tekst_IO . Put_Line ( "[CONSUMER] Opgave startet" ); loopStorage1 . _ få ; ende -løkke ; slutforbruger ; _ begynde null ; endMain ; _