Hlavní navigace

Programování pod Linuxem pro všechny (20)

18. 6. 2004
Doba čtení: 3 minuty

Sdílet

V minulém dílu jsme si vysvětlovali synchronizaci vláken pomocí podmíněné proměnné. Dnes bych vám chtěl ukázat praktické uplatnění této metody.

Abychom problém vyřešili, potřebujeme nějakým způsobem zamknout příznak a podmíněnou proměnnou spolu s mutexem. Linux nám takový mechanismus poskytuje. Každá podmíněná proměnná musí být v konjunkci s mutexem; pokud dodržíme tento postup, bude funkce vlákna logicky poskládána z následujících kro­ků:

  1. Cyklus ve funkci thread_function uzamkne mutex a přečte hodnotu příznaku.
  2. Je-li příznak nastaven, odemkne mutex a provede svůj kód.
  3. Když příznak není nastaven, automaticky se odemkne mutex a vlákno bude čekat na podmíněnou proměnnou.

V uvedeném postupu představuje kritickou vlastnost bod 3, ve kterém operační systém umožňuje odemknout mutex a čekat na podmíněnou proměnnou automaticky, aniž by mělo jiné vlákno možnost intervenovat. Takto je vyloučeno, že by jiné vlákno mohlo změnit hodnotu příznaku a signalizovat změnu podmíněné proměnné mezi tím, kdy funkce thread_function testuje hodnotu příznaku a pak čeká na změnu podmíněné proměnné.

Podmíněná proměnná je reprezentována instancí proměnné typu pthread_cond_t. Každá podmíněná proměnná musí být doprovázena mutexem. V následujícím seznamu naleznete funkce umožňující manipulaci s podmíněnou proměnnou.

  • Funkce pthread_cond_init() inicializuje podmíněnou proměnnou. Prvním argumentem je ukazatel na instanci proměnné pthread_cond_t. Druhým argumentem je ukazatel na objekt definující atributy podmíněné proměnné a je systémem ignorován. Mutex musí být inicializován odděleně.
  • Funkce pthread_cond_sig­nal() signalizuje změnu podmíněné proměnné. Pouze jedno vlákno, které je blokováno podmíněnou proměnnou, bude odblokováno. Pokud není žádné jiné vlákno zablokováno podmíněnou proměnnou, je signál ignorován. Argumentem je ukazatel na instanci proměnné pthread_cond_t. Podobná funkce, pthread_cond_bro­adcast(), odblokuje všechna vlákna, která jsou zablokována podmíněnou proměnnou.
  • Funkce pthread_cond_wait() zablokuje volající vlákno, dokud není signalizována změna podmíněné proměnné. Argumentem je ukazatel na instanci proměnné pthread_cond_t. Druhým argumentem je ukazatel na instanci mutexu pthread_mutex_t. Když je funkce volána, musí už být mutex zablokován volajícím vláknem. Tato funkce automaticky odemkne mutex a zablokuje se podmíněnou proměnnou. Když je signalizována změna podmíněné proměnné a volající vlákno se odblokuje, funkcepthread_con­d_wait() automaticky znovu získá uzamčení mutexu.

Kdykoliv váš program provede akci, jež může změnit smysl podmínky, kterou chráníte prostřednictvím podmíněné proměnné, měl by realizovat následujcí kroky.

  1. Uzamkněte mutex doprovázející podmíněnou proměnnou.
  2. Proveďte kteroukoliv akci, jež by mohla změnit smysl podmínky.
  3. Signalizujte nebo vyšlete podmíněnou proměnnou.
  4. Odemkněte mutex doprovázející podmíněnou proměnnou.

Následující kód obsahuje předcházející verzi našeho příkladu, přičemž nyní se zde používá podmíněná proměnná k ochraně příznaku. Ve funkci thread_function je držen zámek mutexu před kontrolou proměnné thread_flag. Tento zámek se automaticky uvolní voláním funkce pthread_cond_wait() před zablokováním a je poté automaticky získán zpět. Funkce set_thread_flag uzamyká mutex předtím, než se nastaví proměnné thread_flag a než se signalizuje mutex.

#include <pthread.h>

int thread_flag;
pthread_cond_t thread_flag_cv;
pthread_mutex_t thread_flag_mutex;

void inialize_flag()
{
  /* Inicializace mutexu a podminene promenne. */
  pthread_mutex_init(&thread_flag_mutex, NULL);
  pthread_cond_init(&thread_flag_cv, NULL);
  thread_flag = 0;
}

/* Vola funkci do_work pokud je promenna thread_flag nastavena, jinak je blokovana */

void *thread_function(void *thread_arg)
{
  while(1) {
    /* Uzamkne mutex pred zpristupnenim promenne */
    pthread_mutex_lock(&thread_flag_mutex);
    while(!thread_flag)
      /* Podminena promenna neni nastavena. Cekani na signal o zmene hodnoty promenne. Pokud obdrzi signal a uvolni vlakno, probehne smycka a bude zkontrolovana podminena promenna. */
      pthread_cond_wait(&thread_flag_cv, &thread_flag_mutex);
    /* Pokud program postoupil az sem, promenna musi byt nastavena. Odemkne mutex. */
    pthread_mutex_unlock(&thread_flag_mutex);
    /* Zavola funkci do_work */
    do_work();
  }
  return(NULL);
}

/* Nastavi hodnotu podminene promenne FLAG_VALUE */
void set_thread_flag(int flag_value)
{
  /* Uzamkne mutex pred pristupem do podminene promenne */
  pthread_mutex_lock(&thread_flag_mutex);
  /* Nastavi hodnotu podminene promenne a vysle signal o zmene promenne. Jedno vlakno bude odblokovano. */
  thread_flag = flag_value;
  pthread_cond_signal(&thread_flag_cv);
  /* Odemkne mutex */
  pthread_mutex_unlock(&thread_flag_mutex);
} 

Podmínka chráněná podmíněnou proměnnou může být libovolně složitá. Avšak před provedením jakékoliv operace, která může změnit smysl podmínky, by mělo být požadováno uzamčení mutexu a pak by se měla signalizovat podmíněná proměnná.

Tímto bych ukončil kapitolku věnovanou vláknům. Příště se podíváme na sdílenou pamět, která slouží ke komunikaci mezi procesy.

Byl pro vás článek přínosný?

Autor článku