NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Lekce 2 - Vlákna - Příklady vícevláknových aplikací ve VB.NET

V minulé lekci, Vlákna - Úvod do vícevláknových aplikací ve VB.NET, jsme se uvedli do programování vícevláknových aplikací ve VB.NET. Vysvětlili jsme si pojmy jako proces, vlákna a jejich synchronizace. Pracovali jsme s vláknem na třídě Thread z .NET.

V dnešním VB.NET tutoriálu si vyzkoušíme naprogramovat dvě vícevláknové aplikace, ve kterých se naučíme vlákna zakládat, pojmenovat a spouštět.

Tisk jedniček a nul

V naší první vícevláknové aplikaci si ukážeme paralelní běh dvou vláken na střídavém tisku hodnot 1 a 0 do konzole:

Konzolová aplikace
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...

Založme si novou konzolovou aplikaci s názvem TiskJednicek_A_Nul.

Metoda TiskniJednicky()

Do třídy Program si napišme metodu pro tisk hodnoty 1 v nekonečném cyklu while:

Sub TiskniJednicky()
    While True
        Console.Write("1 ")
    End While
End Sub

Metoda TiskNula()

Podobně si přidejme metodu TiskNula(), která bude v nekonečném cyklu tisknout hodnotu 0:

Sub TiskNula()
    While True
        Console.Write("0 ")
    End While
End Sub

Metoda Main()

Nakonec obě metody zavolejme v metodě Main():

Module Module1
    Sub Main()
        TiskniJednicky()
        TiskNula()
    End Sub

    ...
End Module

Testování

Když aplikaci spustíme, vidíme neustálý tisk čísla 1:

Konzolová aplikace
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...

Na tisk čísla 0 se samozřejmě nedostalo, protože jsme zůstali zacykleni v metodě TiskniJednicky(). Pojďme to napravit přidáním dalšího vlákna.

Úprava metody Main()

V metodě Main() vytvoříme nové vlákno pro tisk nuly pomocí třídy Thread:

Imports System.Threading

Module Module1
    Sub Main()
        Dim vlaknoNula As New Thread(AddressOf TiskNula)
        vlaknoNula.Start()

        TiskniJednicky()
    End Sub

    ...
End Module

Nejdříve vytvoříme nové vlákno vlaknoNula, v jehož konstruktoru zavoláme naši metodu TiskNula(). Vlákno vlaknoNula poté spustíme. Nakonec zavoláme metodu TiskniJednicky(), která bude v nekonečném cyklu tisknout hodnotu 1 do konzole.

Testování

Po spuštění aplikace nyní v konzoli vidíme střídání tisku čísel 1 a 0, což dokazuje paralelní běh obou vláken:

Konzolová aplikace
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...

Pořadí tisku 1 a 0 se bude lišit při každém spuštění aplikace.

V ukázce vidíme, jak operační systém poskytuje plánovač vláken. Plánovač vláken rozhoduje o tom, které vlákno má právo vykonat svůj kód. Plánovač může přidělovat časové kvantum každému vláknu. Když jedno vlákno dosáhne konce svého časového kvanta, plánovač přepne na jiné vlákno.

Úkoly

Představme si aplikaci, která zpracovává úkoly v aplikaci. Založme si konzolovou aplikaci s názvem Ukoly. V naší aplikaci bude:

  • První vlákno odpovědné za načtení úkolů ("Načítací vlákno").
  • Druhé vlákno bude provádět načtené úkoly ("Zpracovávací vlákno").

Výstup z aplikace bude vypadat takto:

Konzolová aplikace
[Načítací vlákno pro úkoly] Načítání nových úkolů...
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolů...
[Načítací vlákno pro úkoly] Nové úkoly načteny.
[Načítací vlákno pro úkoly] Přiřazování úkolu: Úkol 1: Implementace nového rozhraní.
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolu 1.
[Načítací vlákno pro úkoly] Přiřazování úkolu: Úkol 2: Testování aplikace.
[Načítací vlákno pro úkoly] Přiřazování úkolu: Úkol 3: Oprava chyb v kódu.
[Načítací vlákno pro úkoly] Všechny úkoly přiřazeny.
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolu 2.
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolu 3.
[Zpracovávací vlákno pro úkoly] Všechny úkoly zpracovány.

Budeme pracovat pouze v modulu Module1.vb.

Pole assignedTasks

Nad metodu Main() deklarujeme pole assignedTasks():

Dim assignedTasks() = {"Úkol 1: Implementace nového rozhraní", "Úkol 2: Testování aplikace", "Úkol 3: Oprava chyb v kódu"}

Metoda NactiUkoly()

V této metodě implementujeme načítání nových úkolů:

Sub NactiUkoly()
    Dim threadName As String = Thread.CurrentThread.Name
    Console.WriteLine($"[{threadName}] Načítání nových úkolů...")
    Thread.Sleep(2000)
    Console.WriteLine($"[{threadName}] Nové úkoly načteny.")


    For Each task As String In assignedTasks
        Console.WriteLine($"[{threadName}] Přiřazování úkolu: {task}")
        Thread.Sleep(1000)
    Next

    Console.WriteLine($"[{threadName}] Všechny úkoly přiřazeny")
End Sub

Nejprve si uložíme název vlákna do proměnné threadName pomocí vlastnosti Thread.CurrentThread.Name. Poté vytiskneme název vlákna do konzole spolu s informacemi o průběhu načítání a přiřazování úkolů.

Metoda ZpracujUkoly()

V této metodě budeme načtené úkoly zpracovávat:

Sub ZpracujUkoly()
    Dim threadName As String = Thread.CurrentThread.Name
    Console.WriteLine($"[{threadName}] Zpracovávání úkolů:")

    For i As Integer = 1 To assignedTasks.Length
        Console.WriteLine($"[{threadName}] Zpracovávání úkolu {i}")
        Thread.Sleep(2000)
    Next

    Console.WriteLine($"[{threadName}] Všechny úkoly zpracovány")
End Sub

Nejprve si uložíme název vlákna do proměnné threadName pomocí vlastnosti Thread.CurrentThread.Name. Poté vytiskneme název vlákna do konzole spolu s informacemi o průběhu zpracování úkolů.

Metoda Main()

A nakonec v metodě Main() obě vlákna spustíme:

    Sub Main()

        Dim nacitaciVlakno As New Thread(AddressOf NactiUkoly)
        nacitaciVlakno.Name = "Načítací vlákno pro úkoly"
        nacitaciVlakno.Start()

        Dim zpracovavaciVlakno As New Thread(AddressOf ZpracujUkoly)
        zpracovavaciVlakno.Name = "Zpracovávací vlákno pro úkoly"
        zpracovavaciVlakno.Start()

        Console.ReadKey()

    End Sub

V metodě vytvoříme vlákna nacitaciVlakno a zpracovavaciVlakno. Do vlastnosti Name vložíme jejich názvy. A pak už jen metodou Start() obě vlákna spustíme.

Testování

Po spuštění aplikace uvidíme výpis práce obou vláken:

Konzolová aplikace
[Načítací vlákno pro úkoly] Načítání nových úkolů...
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolů
[Načítací vlákno pro úkoly] Nové úkoly načteny
[Načítací vlákno pro úkoly] Přiřazování úkolu: Úkol 1: Implementace nového rozhraní
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolu 1
[Načítací vlákno pro úkoly] Přiřazování úkolu: Úkol 2: Testování aplikace
[Načítací vlákno pro úkoly] Přiřazování úkolu: Úkol 3: Oprava chyb v kódu
[Načítací vlákno pro úkoly] Všechny úkoly přiřazeny
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolu 2
[Zpracovávací vlákno pro úkoly] Zpracovávání úkolu 3
[Zpracovávací vlákno pro úkoly] Všechny úkoly zpracovány

V příští lekci, Vlákna - Uspání, blokování a stavy vláken ve VB.NET, se naučíme základy synchronizace vláken ve VB.NET. Ukážeme si, jak vlákna uspat i blokovat, a seznámíme se se stavy vláken.


 

Předchozí článek
Vlákna - Úvod do vícevláknových aplikací ve VB.NET
Všechny články v sekci
Paralelní programování a vícevláknové aplikace v VB.NET
Přeskočit článek
(nedoporučujeme)
Vlákna - Uspání, blokování a stavy vláken ve VB.NET
Článek pro vás napsal Stanislav Zita
Avatar
Uživatelské hodnocení:
1 hlasů
Aktivity