A feltételváltozó egy szinkronizálási primitív , amely egy vagy több szálat blokkol mindaddig, amíg egy másik száltól nem érkezik jel valamely feltétel teljesülésére vonatkozóan, vagy amíg a maximális időtúllépési időszak le nem telik. A feltételváltozók egy kapcsolódó mutex -szel együtt használatosak, és bizonyos típusú monitorok jellemzői .
Elméletileg a feltételváltozó egy megosztott adatobjektumhoz társított szálak sora, amelyek arra várnak, hogy valamilyen feltételt szabjanak az adatállapotra. Így minden feltételváltozóhoz egy utasítás tartozik . Ha egy szál egy feltételváltozón várakozik, akkor nem tekintjük az adatok tulajdonosának, és egy másik szál módosíthatja a megosztott objektumot, és jelezheti a várakozó szálakat, ha az állítás sikeres .
Ez a példa a feltételváltozók használatát mutatja be a gyártói és fogyasztói szálak szinkronizálására. A termelő szál, fokozatosan növelve a megosztott változó értékét, jelzi a feltételváltozón várakozó szálnak, hogy a maximális érték túllépte a feltételt. Egy várakozó fogyasztói szál, amely egy megosztott változó értékét ellenőrzi, blokkol, ha a maximális feltétel nem teljesül. Amikor jelzi, hogy az állítás igaz, a szál "felhasználja" a megosztott erőforrást, csökkentve a megosztott változó értékét, hogy az ne essen a megengedett minimum alá.
A C POSIX Threads könyvtárában a pthread_cond előtaggal ellátott függvények és adatstruktúrák felelősek a feltételváltozók használatáért.
Forráskód C nyelven POSIX Threads használatával #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #define STORAGE_MIN 10 #define STORAGE_MAX 20 /* Megosztott erőforrás */ int tárhely = STORAGE_MIN ; pthread_mutex_t mutex ; pthread_cond_t feltétel ; /* Fogyasztói szál funkció */ érvénytelen * fogyasztó ( érvénytelen * args ) { puts ( "[FOGYASZTÓ] szál elindult" ); int to Fogyasztás = 0 ; míg ( 1 ) { pthread_mutex_lock ( & mutex ); /* Ha a megosztott változó értéke kisebb, mint a maximum, * akkor a szál arra az állapotba kerül, hogy egy jelre vár, hogy * a maximumot elérte */ közben ( tárhely < STORAGE_MAX ) { pthread_cond_wait ( & feltétel , & mutex ); } toConsume = tárhely - STORAGE_MIN ; printf ( "A [FOGYASZTÓ] tárhely maximális, fogyasztása %d \n " , \ toConsume ); /* A megengedett mennyiség "fogyasztása" a megosztott * változó értékéből */ tárolás -= toConsume ; printf ( "[FOGYASZTÓ] tárhely = %d \n " , tárhely ); pthread_mutex_unlock ( & mutex ); } return NULL ; } /* Gyártói szál funkció */ érvénytelen * producer ( érvénytelen * args ) { puts ( "[PRODUCER] szál elindult" ); míg ( 1 ) { usleep ( 200000 ); pthread_mutex_lock ( & mutex ); /* A termelő folyamatosan növeli a megosztott változó értékét */ ++ tárhely ; printf ( "[PRODUCER] tárhely = %d \n " , tárhely ); /* Ha a megosztott változó értéke eléri vagy meghaladja a * maximumot, a fogyasztói szál értesítést kap */ if ( tárhely >= STORAGE_MAX ) { puts ( "[PRODUCER] tárhely maximum" ); pthread_cond_signal ( & feltétel ); } 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 ( & feltétel , NULL ); res = pthread_create ( & thProducer , NULL , producer , NULL ); ha ( res != 0 ) { perror ( "pthread_create" ); kilépés ( EXIT_FAILURE ); } res = pthread_create ( & thConsumer , NULL , fogyasztó , NULL ); ha ( res != 0 ) { perror ( "pthread_create" ); kilépés ( EXIT_FAILURE ); } pthread_join ( thProducer , NULL ); pthread_join ( thConsumer , NULL ); return EXIT_SUCCESS ; }A C++11 szabvány hozzáadta a többszálú feldolgozás támogatását a nyelvhez. A feltételes változókkal való munkavégzést a feltétel_változó fejlécfájlban deklarált eszközök biztosítják
Forrásszöveg C++ nyelven (C++11) #include <cstdlib> #include <iostream> #include <szál> #include <mutex> #include <feltétel_változó> #include <chrono> #define STORAGE_MIN 10 #define STORAGE_MAX 20 int tárhely = STORAGE_MIN ; std :: mutex globalMutex ; std :: feltétel_változó feltétel ; /* Fogyasztói szál funkció */ érvénytelen fogyasztó () { std :: cout << "[FOGYASZTÓ] szál elindult" << std :: endl ; int to Fogyasztás = 0 ; míg ( igaz ) { std :: egyedi_zár < std :: mutex > zár ( globalMutex ); /* Ha a megosztott változó értéke kisebb, mint a maximum, * akkor a szál arra az állapotba kerül, hogy egy jelre vár, hogy * a maximumot elérte */ if ( tárhely < STORAGE_MAX ) { állapot . várjon ( lock , []{ return storage >= STORAGE_MAX ;} ); // Atomikusan _felszabadítja a mutexet_ és azonnal blokkolja a szálat toConsume = storage - STORAGE_MIN ; std :: cout << "[FOGYASZTÓ] a tárhely maximális, fogyaszt" << toConsume << std :: endl ; } /* A megengedett mennyiség "fogyasztása" a megosztott * változó értékéből */ tárolás -= toConsume ; std :: cout << "[FOGYASZTÓ] storage = " << tárhely << std :: endl ; } } /* Gyártói szál funkció */ érvénytelen producer () { std :: cout << "[PRODUCER] szál elindult" << std :: endl ; míg ( igaz ) { std :: this_thread :: sleep_for ( std :: chrono :: milliszekundum ( 200 )); std :: egyedi_zár < std :: mutex > zár ( globalMutex ); ++ tárhely ; std :: cout << "[PRODUCER] storage = " << tárhely << std :: endl ; /* Ha a megosztott változó értéke eléri vagy meghaladja a * maximumot, a fogyasztói szál értesítést kap */ if ( tárhely >= STORAGE_MAX ) { std :: cout << "[PRODUCER] tárhely maximum" << std :: endl ; állapot . notify_one (); } } } int main ( int argc , char * argv []) { std :: szál thProducer ( producer ); std :: szál thConsumer ( fogyasztó ); thProducer . csatlakozz (); thConsumer . csatlakozz (); return 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 külső belső tárhely ; külső QMutex qmt ; külső QWaitCondition feltétel ; osztály Gyártó : public QThread { Q_OBJECT privát : üres futás () { qDebug () << "[PRODUCER] szál elindult" ; míg ( 1 ) { QTread :: msleep ( 200 ); qmt . zár (); ++ tárhely ; qDebug () << "[PRODUCER] storage = " << tárhely ; /* Ha a megosztott változó értéke eléri vagy meghaladja a * maximumot, a fogyasztói szál értesítést kap */ if ( tárhely >= STORAGE_MAX ) { qDebug () << "[PRODUCER] tárhely maximum" ; állapot . wakeOne (); } qmt . kinyit (); } } }; osztály Fogyasztó : nyilvános QThread { Q_OBJECT privát : üres futás () { qDebug () << "[FOGYASZTÓ] szál elindult" ; int to Fogyasztás = 0 ; míg ( 1 ) { qmt . zár (); /* Ha a megosztott változó értéke kisebb, mint a maximum, * akkor a szál arra az állapotba kerül, hogy egy jelre vár, hogy * a maximumot elérte */ if ( tárhely < STORAGE_MAX ) { állapot . vár ( & qmt ); toConsume = tárhely - STORAGE_MIN ; qDebug () << "A [FOGYASZTÓ] tárhelye maximális, fogyaszt" << toConsume ; } /* A megengedett mennyiség "fogyasztása" a megosztott * változó értékéből */ tárolás -= toConsume ; qDebug () << "[FOGYASZTÓ] storage = " << tárhely ; qmt . kinyit (); } } }; #endif /* CW_H */main.cpp
#include <QCoreApplication> #include "cw.h" int tárhely = STORAGE_MIN ; QMutex qmt ; QWaitCondition feltétel ; int main ( int argc , char * argv []) { QCoreApplication alkalmazás ( argc , argv ); termelő prod ; fogyasztói hátrányok ; prod . start (); hátrányok . start (); vissza az alkalmazást . végrehajtó (); }A PythonbanCondition a feltételváltozók a modulosztály példányaiként valósulnak meg threading. A következő példa ugyanazt a feltételváltozót használja a gyártói és fogyasztói szálban a környezetkezelő szintaxis használatával [1]
# Cond_var : # fogyasztói szál cond_var feltétellel , míg nem an_item_is_available (): # míg az elem nem elérhető cond_var . várjon () # várjon get_an_item () # kapja meg az elemet # Producer szál cond_var : # cond_var feltétel kontextusában make_an_item_available ( ) # hozzon létre egy cond_var elemet . értesíteni () # értesíteni a fogyasztókatAz Ada nyelvben nincs szükség feltételváltozók használatára. Lehetőség van védett adattípusok használatával a feladatblokkoló monitorok rendszerezésére.
Ada '95-ös forráskód with Ada.Text_IO ; eljárás Fő az feladat Producer ; -- termelői feladat bevallási feladat Fogyasztó ; -- fogyasztói feladatnyilatkozat a Storage_T típusa 10 .. 20 tartomány ; -- tartomány típusa a megosztáshoz -- a gyártó és a fogyasztó által megosztott monitor (védett objektum) védett típus A tárolás a Put ; -- művelet "termelés" erőforrás egység bejegyzés Get ; -- művelet a megengedett mennyiségű erőforrás bejegyzés értékének "fogyasztására" ( érték : out Storage_T ); -- változó érték accessor private -- rejtett változó minimális kezdőértékkel a StorageData típusú tartományból : Storage_T := Storage_T ' First ; vége Tárolás ; -- Monitoring implementation Storage protected body A tárhely bejegyzés Elhelyezés , amikor StorageData < Storage_T ' Last is start StorageData := StorageData + 1 ; if StorageData >= Storage_T ' Last then Ada . text_IO . Put_Line ( "[PRODUCER] maximális tárhely" ); vége if ; vége ; bejegyzés 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 ( "[FOGYASZTÓ] fogyaszt" ); vége Get ; bejegyzés Érték ( érték : Out Storage_T ) , ha igaz értéke begin val := StorageData ; vége ; vége Tárolás ; - figyelni a példányt Tárolás Tárhely1 : Tárolás ; -- a termelői feladat feladattestének megvalósítása A Producer v : Storage_T ; kezdi Ada . text_IO . Put_Line ( "[PRODUCER] Feladat elindítva" ); hurokkésleltetés 0,2 ; _ Tárolás 1 . tegye ; Tárolás 1 . Érték ( v ); Ada . text_IO . put ( "[PRODUCER]" ); Ada . text_IO . Put_Line ( v ' Img ); end - loop ; végtermelő ; _ -- fogyasztói feladat végrehajtási feladat teste Fogyasztó is kezdődik Ada . text_IO . Put_Line ( "[FOGYASZTÓ] Feladat megkezdve" ); loopStorage1 . _ kap ; end - loop ; vég Fogyasztó ; start null ; endMain ; _