Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Vlákna - Uspání, blokování a stavy vláken v C# .NET

V minulé lekci, Vlákna - Příklady vícevláknových aplikací v C# .NET, jsme si naprogramovali dvě vícevláknové aplikace, ve kterých jsme se naučili vlákna zakládat, pojmenovat a spouštět.

V dnešním C# .NET tutoriálu se naučíme základy synchronizace vláken. Ukážeme si, jak vlákna uspat a blokovat. Představíme si třídu Thread a seznámíme se se stavy vláken. Vše si ukážeme na funkčních příkladech.

Uspaní vláken

V rámci práce s vícevláknovým prostředím nabízí třída Thread užitečné metody pro řízení toku vláken, mezi nimiž patří metoda Sleep(). Metoda Sleep() na třídě Thread se používá pro dočasné pozastavení běhu aktuálního vlákna na definovanou dobu v milisekundách. Typickým použitím je simulace čekání na určitou událost, nebo zpomalení běhu programu.

Pro zápis doby uspání můžeme v parametru metody Sleep() využít strukturu TimeSpan.

Metoda Sleep()

Uspání vlákna na dobu 1 hodiny provedeme takto:

Thread.Sleep(3600000);

Metoda Sleep() s TimeSpan

S využitím struktury TimeSpan uspíme vlákno na stejnou dobu takto:

Thread.Sleep(TimeSpan.FromHours(1));

Blokování vláken

Další užitečnou metodou třídy Thread je metoda Join(). Metoda Join() blokuje volající vlákno, dokud se vlákno reprezentované instancí typu Thread neukončí. Metoda umožňuje synchronizaci vláken a čekání na dokončení určitého vlákna před pokračováním ve zpracování hlavního vlákna. To je užitečné v situacích, kdy potřebujeme vyčkat na dokončení nějaké operace.

Příklad

Nejlépe to uvidíme na příkladu. Založme si novou konzolovou aplikaci. Budeme pracovat pouze ve třídě Program.

Proměnná hodnota

Nejdříve si do třídy Program vložme statickou proměnou hodnota, kterou naplňme hodnotou 0:

static int hodnota = 0;

Metoda PrictiJedna()

Pod metodu Main() si napišme první metodu, kterou budeme volat, metodu PrictiJedna(). V metodě implementujeme zvýšení hodnoty proměnné hodnota o hodnotu 1 a její výpis do konzole:

static void PrictiJedna()
{
    for (int i = 1; i <= 10; i++)
    {
        hodnota += 1;
    }
    Console.WriteLine("Hodnota proměnné: " + hodnota);
}

Metoda OdectiJedna()

Podobně implementujeme metodu OdectiJedna(). V metodě tedy snížíme hodnotu proměnné hodnota o 1 a vypíšeme ji do konzole:

static void OdectiJedna()
{
    for (int i = 1; i <= 10; i++)
    {
        hodnota -= 1;
    }
    Console.WriteLine("Hodnota proměnné: " + hodnota);
}

Metoda Main()

Pomocné metody implementované máme. Můžeme se tedy vrhnout na dokončení programu v metodě Main():

using System;
using System.Threading;

namespace odpocitavadlo
{
    class Program
    {

       static int hodnota = 0;

       static void Main(string[] args)
       {
          Thread pricteniThread = new Thread(PrictiJedna);
          Thread odecitaniThread = new Thread(OdectiJedna);

          pricteniThread.Start();
          pricteniThread.Join();

          odecitaniThread.Start();
          odecitaniThread.Join();

          Console.WriteLine("Výsledek: " + hodnota);
       }
    }
}

Vytvoříme dvě vlákna. Vlákno:

  • pricteniThread, v jehož konstruktoru zavoláme metodu PrictiJedna(),
  • odecitaniThread, v jehož konstruktoru zavoláme metodu OdectiJedna().

Obě vlákna spustíme a poté na nich zavoláme metodu Join(). Nakonec do konzole vytiskneme výslednou hodnotu proměnné hodnota.

Testování

Po spuštění aplikace vidíme, jak se hodnota proměnné hodnota mění:

Konzolová aplikace
Hodnota proměnné: 10
Hdonota proměnné: 0
Výsledek: 0

Stavy vláken

Podívejme se na některé ze stavů, které vlákno může nabývat. Stav vlákna lze zjistit pomocí jeho vlastnosti ThreadState, která je výčtovým typem sestávajícím z jedné nebo více z následujících hodnot:

  • Running – Vlákno je v běhu, provádí svůj kód.
  • StopRequested – Bylo požádáno o zastavení vlákna, ale ještě nebylo zastaveno.
  • SuspendRequested – Bylo požádáno o pozastavení vlákna, ale ještě nebylo pozastaveno.
  • Background – Vlákno je nastaveno jako pozadí.
  • Unstarted – Vlákno bylo vytvořeno, ale ještě nebylo spuštěno.
  • Stopped – Vlákno bylo zastaveno.
  • WaitSleepJoin – Vlákno čeká v režimu spánku nebo na spojení.
  • Suspended – Vlákno bylo pozastaveno.
  • AbortRequested – Bylo požádáno o zrušení vlákna, ale ještě nebylo zrušeno.
  • Aborted – Vlákno bylo zrušeno.

Příklad

Ukažme si výpis stavů vláken na příkladu.

Metoda Counting()

V konzolové aplikaci si napíšeme tuto metodu:

static void Counting()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine(i);
        Thread.Sleep(500);
    }
}

V metodě Counting() provádíme číslování od 0 do 4 s výpisem čísel. Mezi každý výpis vkládáme pauzu trvající 500 milisekund.

Metoda Main()

Do metody Main() přidáme následující kód:

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread thread = new Thread(Counting);
        Console.WriteLine("Stav vlákna po vytvoření: " + thread.ThreadState);

        thread.Start();
        Console.WriteLine("Stav vlákna po spuštění: " + thread.ThreadState);

        Thread.Sleep(100);
        Console.WriteLine("Stav vlákna po chvilce čekání: " + thread.ThreadState);

        thread.Join();
        Console.WriteLine("Stav vlákna po dokončení: " + thread.ThreadState);
    }

}

V metodě Main() vytváříme nové vlákno pomocí třídy Thread a jejího konstruktoru, kterému předáváme metodu Counting(). Poté vypisujeme stav vlákna pomocí vlastnosti ThreadState v různých bodech životního cyklu vlákna.

Stav vlákna je zajímavý pouze ve scénářích ladění. Kód by nikdy neměl používat stav vlákna k synchronizaci aktivit vláken.

Testování

Spuštěním kódu uvidíme výpis stavů vláken:

Konzolová aplikace
Stav vlákna po vytvoření: Unstarted
Stav vlákna po spuštění: Running
0
Stav vlákna po chvilce čekání: WaitSleepJoin
1
2
3
4
Stav vlákna po dokončení: Stopped

V příští lekci, Vlákna - Bezpečnost vláken v C# .NET, se budeme zabývat bezpečností vláken v C# .NET. Vybereme si jednu techniku sdílení dat mezi vlákny, kterou implementujeme do příkladu.


 

Předchozí článek
Vlákna - Příklady vícevláknových aplikací v C# .NET
Všechny články v sekci
Paralelní programování a vícevláknové aplikace v C# .NET
Přeskočit článek
(nedoporučujeme)
Vlákna - Bezpečnost vláken v C# .NET
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
85 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity