Ehtomuuttuja on synkronointiprimitiivi , joka estää yhden tai useamman säikeen , kunnes toiselta säikeeltä vastaanotetaan signaali jonkin ehdon täyttymisestä tai kunnes enimmäisaikakatkaisujakso on kulunut. Ehtomuuttujia käytetään yhdessä siihen liittyvän mutexin kanssa, ja ne ovat ominaisuus tietyissä monitoreissa .
Käsitteellisesti ehtomuuttuja on jono jaettuun tietoobjektiin liittyviä säikeitä, jotka odottavat jonkin ehdon asettamista tietotilaan. Siten jokainen ehtomuuttuja liittyy lauseeseen . Kun säie odottaa ehtomuuttujaa, sen ei katsota omistavan tietoja, ja toinen säie voi muokata jaettua objektia ja ilmoittaa odottaville säikeille, jos väite onnistuu .
Tämä esimerkki havainnollistaa ehtomuuttujien käyttöä tuottaja- ja kuluttajasäikeiden synkronointiin. Tuottajasäie, joka lisää asteittain jaetun muuttujan arvoa, signaloi ehtomuuttujaa odottavalle säikeelle, että maksimiarvo ylitetty ehto täyttyy. Odottava kuluttajasäie, joka tarkistaa jaetun muuttujan arvon, estää, jos maksimiehto ei täyty. Kun väite on totta, säie "kuluttaa" jaetun resurssin vähentäen jaetun muuttujan arvoa, jotta se ei putoa alle sallitun minimin.
C: n POSIX Threads -kirjastossa funktiot ja tietorakenteet, joiden etuliite on pthread_cond, vastaavat ehtomuuttujien käytöstä.
Lähdekoodi C-kielellä POSIX-säikeitä käyttäen #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #define STORAGE_MIN 10 #define STORAGE_MAX 20 /* Jaettu resurssi */ int tallennustila = STORAGE_MIN ; pthread_mutex_t mutex ; pthread_cond_t- ehto ; /* Kuluttajalankatoiminto */ void * kuluttaja ( void * args ) { puts ( "[KULUTTAJA] säie aloitettu" ); int kuluttaa = 0 ; kun ( 1 ) { pthread_mutex_lock ( & mutex ); /* Jos jaetun muuttujan arvo on pienempi kuin maksimi, * säie siirtyy tilaan odottaa signaalia, että * maksimi on saavutettu */ kun ( tallennustila < STORAGE_MAX ) { pthread_cond_wait ( & ehto , & mutex ); } toConsume = tallennustila - STORAGE_MIN ; printf ( "[CONSUMER] tallennustila on suurin, kuluttaa %d \n " , \ toConsume ); /* Sallitun määrän "kulutus" jaetun * muuttujan */ arvosta varastointi -= toConsume ; printf ( "[KULUTTAJA] tallennustila = %d \n " , tallennustila ); pthread_mutex_unlock ( & mutex ); } return NULL ; } /* Tuottajan lankatoiminto */ void * tuottaja ( void * args ) { puts ( "[TUOTTAJA] säie aloitettu" ); kun ( 1 ) { usleep ( 200000 ); pthread_mutex_lock ( & mutex ); /* Tuottaja kasvattaa jatkuvasti jaetun muuttujan arvoa */ ++ varastointi ; printf ( "[TUOTTAJA] tallennustila = %d \n " , tallennustila ); /* Jos jaetun muuttujan arvo saavuttaa tai ylittää * maksimiarvon, kuluttajaketju saa ilmoituksen */ jos ( tallennustila >= STORAGE_MAX ) { laittaa ( "[TUOTTAJA] tallennustila maksimi" ); pthread_cond_signal ( & ehto ); } pthread_mutex_unlock ( & mutex ); } return NULL ; } int main ( int argc , char * argv []) { int res = 0 ; pthread_t thProducer , thConsumer ; pthread_mutex_init ( & mutex , NULL ); pthread_cond_init ( & ehto , NULL ); res = pthread_create ( & thTuottaja , NULL , tuottaja , NULL ); jos ( res != 0 ) { perror ( "pthread_create" ); exit ( EXIT_FAILURE ); } res = pthread_create ( & thConsumer , NULL , kuluttaja , NULL ); jos ( res != 0 ) { perror ( "pthread_create" ); exit ( EXIT_FAILURE ); } pthread_join ( thProducer , NULL ); pthread_join ( thConsumer , NULL ); paluu EXIT_SUCCESS ; }C++11-standardi lisäsi kieleen monisäikeen tuen. Ehdollisten muuttujien kanssa työskentely tapahtuu otsikkotiedostossa condition_variable ilmoitetuilla tavoilla
Lähdeteksti kielellä C++ (C++11) #include <cstdlib> #include <iostream> #sisällytä <ketju> #sisällytä <mutex> #include <ehtomuuttuja> #include <chrono> #define STORAGE_MIN 10 #define STORAGE_MAX 20 int tallennustila = STORAGE_MIN ; std :: mutex globalMutex ; std :: ehtomuuttuja ehto ; /* Kuluttajalankatoiminto */ mitätön kuluttaja () { std :: cout << "[KULUTTAJA] säie aloitettu" << std :: endl ; int kuluttaa = 0 ; kun ( tosi ) { std :: ainutlaatuinen_lukko < std :: mutex > lukko ( globalMutex ); /* Jos jaetun muuttujan arvo on pienempi kuin maksimi, * säie siirtyy tilaan odottaa signaalia, että * maksimi on saavutettu */ jos ( tallennustila < STORAGE_MAX ) { kunto . odota ( lock , []{ palauta tallennustila >= STORAGE_MAX ;} ); // Atomisesti _vapauttaa mutexin_ ja välittömästi estää säikeen toConsume = varastointi - STORAGE_MIN ; std :: cout << "[KULUTTAJA] tallennustila on maksimi, kuluttaa" << toConsume << std :: endl ; } /* Sallitun määrän "kulutus" jaetun * muuttujan */ arvosta varastointi -= toConsume ; std :: cout << "[KULUTTAJA] varasto = " << tallennustila << std :: endl ; } } /* Tuottajan lankatoiminto */ tyhjä tuottaja () { std :: cout << "[TUOTTAJA] säie aloitettu" << std :: endl ; kun ( tosi ) { std :: this_thread :: sleep_for ( std :: krono :: millisekuntia ( 200 )); std :: ainutlaatuinen_lukko < std :: mutex > lukko ( globalMutex ); ++ varastointi ; std :: cout << "[TUOTTAJA] storage = " << tallennustila << std :: endl ; /* Jos jaetun muuttujan arvo saavuttaa tai ylittää * maksimiarvon, kuluttajaketju saa ilmoituksen */ jos ( tallennustila >= STORAGE_MAX ) { std :: cout << "[TUOTTAJA] tallennustila maksimi" << std :: endl ; kunto . notify_one (); } } } int main ( int argc , char * argv []) { std :: säiettä thProducer ( tuottaja ); std :: lanka thConsumer ( kuluttaja ); thProducer . liity (); thConsumer . liity (); paluu 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 ulkoinen sisäinen varastointi ; ulkoinen QMutex qmt ; ulkoinen QWaitCondition ehto ; luokka Tuottaja : public QThread { Q_OBJECT yksityinen : tyhjä juoksu () { qDebug () << "[TUOTTAJA] säie aloitettu" ; kun ( 1 ) { QThread :: msleep ( 200 ); qmt . lukko (); ++ varastointi ; qDebug () << "[TUOTTAJA] tallennustila = " << tallennustila ; /* Jos jaetun muuttujan arvo saavuttaa tai ylittää * maksimiarvon, kuluttajaketju saa ilmoituksen */ jos ( tallennustila >= STORAGE_MAX ) { qDebug () << "[TUOTTAJA] tallennustila maksimi" ; kunto . wakeOne (); } qmt . avaa lukitus (); } } }; luokka Kuluttaja : julkinen QThread { Q_OBJECT yksityinen : tyhjä juoksu () { qDebug () << "[KULUTTAJA] säie aloitettu" ; int kuluttaa = 0 ; kun ( 1 ) { qmt . lukko (); /* Jos jaetun muuttujan arvo on pienempi kuin maksimi, * säie siirtyy tilaan odottaa signaalia, että * maksimi on saavutettu */ jos ( tallennustila < STORAGE_MAX ) { kunto . odota ( & qmt ); toConsume = tallennustila - STORAGE_MIN ; qDebug () << "[CONSUMER]-tallennustila on suurin, kuluttaa" << toConsume ; } /* Sallitun määrän "kulutus" jaetun * muuttujan */ arvosta varastointi -= toConsume ; qDebug () << "[KULUTTAJA] tallennustila = " << tallennustila ; qmt . avaa lukitus (); } } }; #endif /* CW_H */main.cpp
#include <QCoreApplication> #include "cw.h" int tallennustila = STORAGE_MIN ; QMutex qmt ; QWaitCondition tila ; int main ( int argc , char * argv []) { QCoreApplication- sovellus ( argc , argv ); Tuottaja prod ; kuluttajien haitat ; prod . aloita (); haittoja . aloita (); palauta sovellus . suorittaja (); }Pythonissa ehtomuuttujat toteutetaan moduuliluokan Conditionilmentyminä threading. Seuraava esimerkki käyttää samaa ehtomuuttujaa tuottaja- ja kuluttajasäikeissä käyttäen kontekstinhallintasyntaksia [1]
# Kuluttajasäie , jossa on cond_var : # cond_var-ehdon yhteydessä, mutta ei an_item_is_available (): # kun kohde ei ole käytettävissä cond_var . odota () # odota get_an_item () # hanki tuote # Tuottajasäie cond_var : lla : # cond_var-ehdon yhteydessä make_an_item_available () # tuottaa cond_var- kohteen . ilmoittaa () # ilmoittaa kuluttajilleAda - kielessä ehtomuuttujia ei tarvitse käyttää. On mahdollista käyttää suojattuja tietotyyppejä tehtävien estomonitoreiden järjestämiseen.
Ada '95 lähdekoodi kanssa Ada.Text_IO ; menettely Main on tehtävä Tuottaja ; - tuottajatehtäväilmoitustehtävä Kuluttaja ; -- kuluttajan tehtäväilmoitus tyyppi Storage_T on alue 10 .. 20 ; -- jaon alueen tyyppi -- tuottajan ja kuluttajan suojatun tyypin jakama monitori (suojattu kohde) Varastointi on syöttö Put ; -- operaatio "tuottaa" resurssiyksikön merkintä Get ; -- toiminto "kuluttaa" sallitun määrän resurssisyöttöä Arvo ( val : out Storage_T ) ; -- muuttujan arvon aksessori yksityinen -- piilotettu muuttuja , jolla on pienin alkuarvo StorageData : Storage_T := Storage_T ' First ; loppu Varastointi ; -- valvoa toteutusta Tallennussuojattu runko Tallennus on syöttö Laita kun StorageData < Storage_T ' Last is alkaa StorageData := StorageData + 1 ; if StorageData >= Storage_T ' Last then Ada . text_IO . Put_Line ( "[TUOTTAJA] tallennustila maksimi" ); loppu jos ; loppu ; merkintä Hanki kun 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 ( "[KULUTTAJA] kuluttaa" ); loppu Hanki ; merkintä Arvo ( arvo : Out Storage_T ) , kun tosi on begin val := StorageData ; loppu ; loppu Varastointi ; - valvoa ilmentymää Storage Storage1 : Storage ; - tuottajatehtävän tehtävärungon toteutus Tuottaja on v : Storage_T ; aloita Ada . text_IO . Put_Line ( "[TUOTTAJA] Tehtävä aloitettu" ); silmukan viive 0,2 ; Varastointi 1 . laittaa ; Varastointi 1 . Arvo ( v ); Ada . text_IO . laittaa ( "[TUOTTAJA]" ); Ada . text_IO . Put_Line ( v ' Img ); end - silmukka ; loppu Tuottaja ; - kuluttajatehtävän toteutustehtävärunko Kuluttaja alkaa Ada . _ text_IO . Put_Line ( "[KULUTTAJA] Tehtävä aloitettu" ); loopStorage1 . _ saada ; end - silmukka ; loppu Kuluttaja ; alkaa null ; endMain ; _