Hlavní navigace

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

Jakub Matys

Dnes se podíváme na asynchronně a synchronně zrušitelná vlákna a nezrušitelná vlákna.

Vlákno často obsahuje kód, který se buď musí realizovat celý, nebo vůbec. Může například alokovat nějaké zdroje, použít je a poté je dealokovat. Když bude takovéto vlákno přerušeno uprostřed své činnosti, mohou použité zdroje zůstat alokovány. Abychom mohli takové situaci předcházet, je možné rozhodovat, zda má být vlákno zrušeno a kdy.

Vlákno může být v jednom ze tří možných stavů s ohledem na možnost jeho zrušení:

  • Vlákno může být asynchronně zrušitelné – může být zrušeno v kterémkoliv svém stavu.
  • Vlákno může být synchronně zrušitelné – může být zrušeno, ale ne ve všech svých stavech. Požadavky na zrušení se ukládají do fronty a vlákno je zrušeno, až provádění kódu dospěje do místa, které to umožňuje.
  • Vlákno může být nezrušitelné – pokusy o zrušení vlákna se ignorují.

V okamžiku vzniku je každé vlákno synchronně zrušitelné.

Synchronní a asynchronní vlákna

Asynchronně zrušitelné vlákno může být zrušeno v kterémkoliv okamžiku své realizace. Synchronně zrušitelné vlákno může být zrušeno jen v určitých okamžicích. Místa, ve kterých může být vlákno zrušeno, se nazývají body zrušení (cancellation points). Takové vlákno bude ukládat požadavky na přerušení do fronty a zruší se až po dosažení bodu zrušení.

Vlákno můžete učinit asyncronně zrušitelné pomocí funkce pthread_setcan­celtype(). Tato funkce má vliv pouze na vlákno, které ji volá. Prvním argumentem funkce musí býtPTHREAD_CAN­CEL_ASYNCHRONO­US (pak bude vlákno asynchonně zrušitelné) nebo PTHREAD_CANCEL_DE­FERRED (vlákno pak bude syncronně zrušitelné). Druhý argument, pokud není nulový, je ukazatel na proměnnou, která obdrží předcházející typ zrušení vlákna. Následující příkaz učiní vlákno asynchronně zrušitelné.

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 

Co tvoří bod zrušení a jak se definuje? Nejjednoduší způsob, jak vytvořit bod zrušení, spočívá ve volání funkce pthread_testcan­cel(). Tato funkce nedělá nic jiného, než že zpracovává požadavky na zrušení čekající ve frontě. Funkci pthread_testcan­cel() byste měli vkládat periodicky do kódu funkce obsahující zdlouhavé výpočty tam, kde může být vlákno zrušeno bez dealokace systémových zdrojů.

Existují také funkce, které samy o sobě představují body zrušení. Jejich seznam najdete v manuálových stránkách pthread_cancel.

Nezrušitelné kritické sekce

Vlákno může znemožit své vlastní zrušení pomocí funkce pthread_setcan­celstate(). Podobně jako v případě pthread_setcan­celtype() má i tato funkce vliv pouze na volající vlákno. Prvním argumentem je PTHREAD_CANCEL_DI­SABLE (znemožnění zrušení vlákna) nebo PTHREAD_CANCEL_E­NABLE (opětovné umožnění zrušení vlákna). Následující volání například znemožní zrušení ve volajícím vlákně:

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 

Funkce pthread_setcan­celstate() vám umožní implentovat tzv. kritickou sekci. Kritická sekce je část kódu, která musí být buď realizována celá, nebo vůbec ne. Jinými slovy jakmile začalo vlákno realizovat kritickou sekci, musí ji dokončit, aniž by mohlo být zrušeno.

Předpokládejme například, že píšete kód pro bankovní program, který transferuje peníze z jednoho účtu na druhý. To znamená, že musíte přidat nějakou hodnotu do bilance na jednom účtu a odečíst tutéž hodnotu z druhého účtu. Kdyby mohlo být vlákno zrušeno v nějakém kritickém místě mezi těmito dvěma operacemi, pak by se asi zhoršovalo renomé banky. Abyste takové situaci zabránili, umístěte zmíněný kód do kritické sekce.

Popsaný transfer peněz můžete implentovat funkcí process_transac­tion(), jejíž ukázka je níže. Tato funkce znemožní zrušení vlákna na začátku kritické sekce, tedy před tím, než se modifikuje bilance kteréhokoliv účtu.

#include <pthread.h>
#include <stdio.h>
#include <string.h>

/* pole zustatku na uctech, indexovane cisly uctu */
float *account_balances;

/* Prevede EURO z uctu FROM_ACCT na ucet TO_ACCT.
   Vraci 0, pokud byla transakce provedena uspesne,
   nebo 1, pokud je zustatek na uctu FROM_ACCT
   prilis maly
 */

int process_transaction (int from_acct, int to_acct, float euro)
{
  int old_cancel_state;
  /* Kontrola zustatku na uctu FROM_ACCT */
  if (account_balances[from_acct] < euro )
     return(1);

  /* zacatek kritikce sekce */
  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cancel_state);
  /* prevod penez */
  account_balances[to_acct] += euro;
  account_balances[from_acct] -= euro;
  /* konec kriticke sekce */
  pthread_setcancelstate (old_cancel_state, NULL);

  return(0);
} 

Všiměte si, že je nutné obnovit starý stav zrušení na konci kritické sekce místo bezpodmínečného nastavení na PTHREAD_CANCEL_E­NABLE. Tím je umožněno, aby se funkce process_transac­tion() volala bezpečně uvnitř ktrékoliv jiné kritické sekce – v tomto případě naše funkce opustí stav zrušení stejným způsobem, jakým jej nabyla.

To by bylo pro dnešek vše, příště se podíváme na data specifická pro vlákna.

Našli jste v článku chybu?

22. 2. 2016 16:12

ViSoft (neregistrovaný)

Chápu to správně, že kritická sekce má smysl pouze u asynchronně zrušitelného vlákna?

4. 5. 2004 10:08

Honza (neregistrovaný)

Taky je dost divné, že když si napíšu vlastní PAM aplikaci (která jen ověřuje login a heslo a nic potom nedělá), tak s tím mým modulem (co ho linkuju -lpthread) normálně funguje i na tom SuSE 8.2 s glibc 2.3, zatímco su neprojde a zakousne se. Zdá se, že lpthread + SuSE 8.2 + su = velká ostuda.

Vitalia.cz: Nestlé vyvinulo nový typ „netloustnoucího“ cukru

Nestlé vyvinulo nový typ „netloustnoucího“ cukru

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Vitalia.cz: Proč vás každý zubař posílá na dentální hygienu

Proč vás každý zubař posílá na dentální hygienu

Podnikatel.cz: Snížení DPH na 15 % se netýká všech

Snížení DPH na 15 % se netýká všech

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

Vitalia.cz: Jmenuje se Janina a žije bez cukru

Jmenuje se Janina a žije bez cukru

Podnikatel.cz: Udávání kvůli EET začalo

Udávání kvůli EET začalo

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?