Poznáváme C# a Microsoft. NET 52. díl – ThreadPool

Dnešní díl navazuje na použití vláken, které je již několik dílů seriálů probíráno a bude se zabývat zajímavou cestou k jednodušší implementaci asynchronních operací prostředí .NET.
Poznáváme C# a Microsoft. NET 52. díl – ThreadPool

Vlákna typu démon

Jelikož se v tomto díle budu zaobírat použitím třídy ThreadPool, dozvíme se co jsou vlákna typu démon a jakým způsobem tyto vlákna vytvořit, protože to s využitím třídy ThreadPool úzce souvisí.

Vlákna typu démon nejsou nic složitého ani nic nového, co by se poprvé objevilo s příchodem platformy .NET. Vlákna můžeme s určitého pohledu dělit na dva druhy, kde prvním jsou vlákna hlavní a druhým jsou právě vlákna typu démon. Hlavní vlákna zařizují hlavní operace aplikace, a pokud je alespoň jedno hlavní vlákno běžící, aplikace neskončí.

Přesným opakem jsou vlákna typu démon, která jsou určena k provádění pomocných operací jakoby „na pozadí“ a tyto operace nejsou natolik důležité, aby kvůli nim nemohla aplikace skončit. To ve výsledku znamená, že pokud skončí poslední běžící hlavní vlákno, tak je běh aplikace ukončen bez ohledu na to, kolik ještě běží vláken typu démon.

A jak takováto vlákna v prostředí .NET vytvořit, ukazuje následující zdrojový kód.

/// <summary>
/// Priklad na pouziti vlaken typu demon
/// </summary>
internal class BackgroundThreads
{
  internal static void Run()
  {
    Thread lThread = new Thread(new ThreadStart(DaemonMethod));
    //nastavime vlaknu, ze je demon
    lThread.IsBackground = true;
    lThread.Start();
    System.Windows.Forms.MessageBox.Show("Pro skonceni behu hlavniho vlakna stisknete OK");
  }
   
  static void DaemonMethod()
  {
    for (char ch = `a`; ch < `z`; ch++)
    {
      Console.WriteLine("DaemonMethod : " + ch);
      Thread.Sleep(400);
    }            
  }
}

Je to velmi snadné, protože ve skutečnosti využijeme pouze instanční vlastnost třídy Thread, kterou je IsBackground, které pokud nastavíme hodnotu true, tak s ní .NET runtime bude nakládat jako s vláknem typu démon. Takže pokud pokud je běh hlavního vlákna dokončen, tak bez ohledu na to jestti námi spuštěné druhé vláknoještě běží je aplikace ukončena.

Použití třídy ThreadPool

Během několika předchozích dílů jsme se zabývali vytvářením nových vláken, jejich spouštěním a v neposlední řadě, také jejich řízením. .NET framework nám umožňuje se velké části těchto operací nevěnovat a nechat ji na starost běhovému prostředí. Samozřejmě není vždy možné se těmto operacím nevěnovat, protože jistě narazíte na spoustu situací, ve kterých bude potřeba si řízení vláken obstarat způsobem, který jsem popisoval v předchozích dílech. Ale v případě jednoduchých situací, můžeme ponechat detaily na běhovém prostředí a směle využít třídu ThreadPool.

Třída ThreadPool nám reprezentuje pool, nebo jinými slovy,“zásobník” vláken, které řídí běhové prostředí a my pomocí rozhraní této třídy běhovému prostředí pouze sdělujeme, že bychom chtěli určitou metodu zavolat asynchronně, jakmile to bude možné. Možné to bude v případě, že se v poolu nachází nějaké vlákno, které je volné, což znamená, že právě nezpracovává nějakou operaci.

ThreadPool je jedinečný pro proces CLR, ve kterém jsou obsaženy aplikační domény a to mimo jiné umožňuje běhovému prostředí optimalizovat použití vláken z poolu jednotlivými .NET aplikacemi. To pro nás znamená, že v mnoha případech, kdy potřebujeme implementovat provádění asynchronních operací, představuje použití ThreadPoolu nejjednodušši a nejlepší cestu.

Po teoretickém představení ThreadPoolu se nyní podívejme na jeho použití v praxi.

/// <summary>
/// Pouziti tridy ThreadPool pro snadnejsi praci s vlakny
/// </summary>
internal class ThreadPoolExample
{
  internal static void Run()
  {
    WaitCallback lCallBack = new WaitCallback(ThreadMethod);
    //sdelime systemu, ze metodu asociovanou
    //s predanym delegatem ma spustit asynchronne
    ThreadPool.QueueUserWorkItem(lCallBack, "At zije ThreadPool :-)");
    //vyckame, nez je systememem spusteno
    //druhe vlakno a provede svou praci
    Thread.Sleep(1000);
    Console.WriteLine("Hlavni vlakno konci svou cinnost");
  }

  static void ThreadMethod(object data)
  {
    Console.WriteLine("Metoda ThreadMethod byla zavolana s daty : {0}", data);
  }
}

Použití třídy ThreadPool pro spuštění metody asynchronně v jiném vláknu je velmi jednoduché, což je také jejím posláním (odstítnit od problematiky řízení vláken, aby se mohl vývojář věnovat implementaci aplikační logiky). K realizaci vyčlenení vlastního vlákna pro provedení operace, pouze využijeme metodu QueueUserWorkItem, která přijímá instanci delegáta WaitCallBack, který předepisuje rozhraní metody na návratový typ void a jeden vstupní parametr obecného typu object, jež se používá k předání dat metodě spuštěné vláknem. K předání dat do metody asociované s delegátem WaitCallBack použijeme druhý parametr metody QueueUserWorkItem. V případě našeho příkladu jsou metodě spouštěné v separátním vláknu předána data v podobě řetězce "At zije ThreadPool :-)".

Možná se divíte, proč je v příkladu použita metoda Sleep pro počkání na provedení asynchronních operací vykonávaných metodou ThreadMethod. Je tomu tak z důvodu, že by byla aplikace ukončena dříve, než by běhové prostředí zařídilo vykonání metody ThreadMethod v novém vlákně a to protože jsou všechna vlákna spouštěná pomocí třídy ThreadPool typu démon, tudíž se na dokončení činnosti, kterou tato vlákna vykonávají, vůbec nečeká.

Informace o thread poolu

Jistě mnohé z vás napadlo, kolik je tedy vlastně v poolu běhového prostředí k dispozici vláken nebo jaký je maximální počet vláken, které mohou být v poolu. Odpověď na obě tyto otázky vám zodpoví metody GetAvailableThreads a GetMaxThreads, které jsou použity v následujícím příkladu.

/// <summary>
/// Ukazka zjisteni informaci o poctu vlaken ThreadPoolu
/// </summary>
internal class ThreadPoolInfo
{
  internal static void Run()
  {
    int lAvailThreads;
    int lAvailIOThreads;
    int lMaxThreads;
    int lMaxIOThreads;
    ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod));
    //pockame nez runtime spusti vlakno
    Thread.Sleep(300);
    ThreadPool.GetAvailableThreads(out lAvailThreads,out lAvailIOThreads);
    ThreadPool.GetMaxThreads(out lMaxThreads, out lMaxIOThreads);
    Console.WriteLine("Pocet volnych vlaken : {0}, Pocet vlaken pro provadeni asynn. IO operaci : {1}", lAvailThreads, lAvailIOThreads);
    Console.WriteLine("Max. pocet vlaken : {0}, Max.pocet vlaken pro provadeni asynn. IO operaci : {1}", lMaxThreads, lMaxIOThreads);
    Thread.Sleep(1000);
    Console.WriteLine("Cinnost hlavniho vlakna skoncila");
  }

  static void ThreadMethod(object data)
  {
    Console.WriteLine("Metoda ThreadMethod byla zavolana.");
    Thread.Sleep(1000);
  }
}

Nás hlavně zajímá první údaj vracený výstupním parametrem obou metod, který říká kolik je v danou chvíli k dispozici volných vláken respektive, jaký je maximální počet vláken. Jelikož je v příkladu spuštěna jedna asychronní úloha, tak by se měl údaj o max. počtu vláken a počtu vláken k dipozici lišit.

Příklady ke článku si můžete stáhnout zde.

Témata článku: Software, Microsoft, Windows, Programování, Pool, Demon, IO

1 komentář

Nejnovější komentáře

  • Pavel Polívka 24. 11. 2007 13:47:09
    Programovou oflline verzi seriálu naleznete ke stažení na...
Určitě si přečtěte

Pojďme programovat elektroniku: Postavíme si titěrnou Wi-Fi meteostanici s lepším teploměrem než Netatmo

Pojďme programovat elektroniku: Postavíme si titěrnou Wi-Fi meteostanici s lepším teploměrem než Netatmo

** Dnes se podíváme na maličkou Wi-Fi destičku Wemos D1 mini ** A připojíme k ní barometrický a teplotní shield ** Poběží na ní web a nabídne i JSON API

18.  6.  2017 | Jakub Čížek | 27

Jak vybrat monitor k počítači: nenechte se zlákat nepodstatnými parametry

Jak vybrat monitor k počítači: nenechte se zlákat nepodstatnými parametry

** Na jaké parametry se zaměřit a kde vás výrobci chtějí nachytat ** Monitory se stále více specifikují pro konkrétní určení ** Náročný hráč nebo profesionální grafik mají různé požadavky

20.  6.  2017 | Tomáš Holčík | 29

Dlouhodobý test HTC Vive: co vám recenze o virtuální realitě neřeknou

Dlouhodobý test HTC Vive: co vám recenze o virtuální realitě neřeknou

** Ani hry se sebelepší grafikou vás nevtáhnou tolik, jako ve virtuální realitě ** Pro sledování filmů není VR ani zdaleka ideální ** I první generace je skvělá, stále však působí jako prototyp

20.  6.  2017 | Stanislav Janů | 19


Aktuální číslo časopisu Computer

Bojujeme proti Fake News

Dva velké testy: fotoaparáty a NASy

Co musíte vědět o změně evropského roamingu

Radíme s výběrem základní desky