Vo formulári sú umiestnené dve tlačidlá s popisom "Start thread 1" a "Start thread 1". Po stlačení každého sa naštartuje jedno vlákno, ktoré inkrementuje svoju vlastnú premennú "i1" a "i2". Zmenu hodnoty možno ihneď pozorovať v labeloch pod každým tlačidlom. Zastavovať a rozbehnúť je možné každé vlákno zvlášť tlačidlami "Stop thread 1" a "Stop thread 2". Aplikácia je v princípe jednoduchá, ide iba o najľahšiu demonštráciu/ukážku práce s vláknami pre programátora. Detailný popis jednotlivého kódu je na dlhšie. V princípe napoviem iba, že využívam v tomto prípade tzv. "callback" funkciu, ktorá spustí asynchrónne napr. SetText1 funkciu pretože nastavenie mnohých vizuálnych vlastností objektov sa vykonáva pomocou tzv. messages - správ, kôli synchronizácii poradia prekreslenia jednotlivých objektov. Aby mohlo takéto vlákno bezpečne nastavovať inkrementovanú hodnotu vo vlastnosti text objektu label. Ďalej stojí za povšimnutie v zdrojovom kóde v metóde DoThread1() použitie statickej metódy triedy vlákna Thread.Sleep(1), ktorou dovolíme na 1 milisekundu urobiť niečo aj ostatným vláknam a premenné "private volatile bool Thread1Running" a "private volatile bool Thread2Running" sú označené kľúčovým slovom "volatile", kde povieme, že chceme, aby mohlo k nim pristupovať viac vlákien. V tomto prípade primárne a ďalšie, nami naštartované tlačidlom. Premenné Thread1Running a Thread2Running používam na kontrolu chodu vlákien - zastavenie.
Po vytvorení oknovej aplikácie si pomenujte a nastavte nasledovné vlastnosti v programe takto:
Assembly name: Threads
Default namespace: Threads
Target framework: .NET Framework 4 Client Profile
Output type: Windows Application
Takže vytvoril som si jednoduchý formulár s menom "Threadform" s ďalšími objektami.
Object: form Name: Threadform Text: Threads
Tlačidlá na štart vlákien:
Object: button Name: button1 Text: Start thread 1
Object: button Name: button2 Text: Start thread 2
Labely/texty na zobrazenie behu vlákien:
Object: label Name: label_thread1 Text: 0
Object: label Name: label_thread2 Text: 0
Tlačidlá na ukončenie vlákien:
Object: button Name: button3 Text: Stop thread 1
Object: button Name: button4 Text: Stop thread 2
Tieto objekty si rozmiestnite na formulári do riadku v poradí:
button1 - button2
label_thread1 - label_thread2
button3 - button4
Kód v c#:
using System; //using System.Collections.Generic; //using System.ComponentModel; //using System.Data; //using System.Drawing; //using System.Linq; //using System.Text; using System.Windows.Forms; using System.Threading; namespace Threads { public partial class Threadform : Form { private int i1 = 0; private int i2 = 0; private volatile bool Thread1Running = false; private volatile bool Thread2Running = false; private Thread Thread1; private Thread Thread2; delegate void SetTextCallback1(string text); delegate void SetTextCallback2(string text); public Threadform() { InitializeComponent(); } private void StartThread1() { if (this.Thread1 == null) { this.Thread1Running = true; this.Thread1 = new Thread(new ThreadStart(this.DoThread1)); this.Thread1.Name = "Thread1"; this.Thread1.Priority = ThreadPriority.BelowNormal; this.Thread1.Start(); } } private void EndThread1() { this.Thread1Running = false; if (this.Thread1 != null) { this.Thread1.Abort(); this.Thread1 = null; } } private void StartThread2() { if (this.Thread2 == null) { this.Thread2Running = true; this.Thread2 = new Thread(new ThreadStart(this.DoThread2)); this.Thread2.Name = "Thread2"; this.Thread2.Priority = ThreadPriority.BelowNormal; this.Thread2.Start(); } } private void EndThread2() { this.Thread2Running = false; if (this.Thread2 != null) { this.Thread2.Abort(); this.Thread2 = null; } } private void DoThread1() { while (this.Thread1Running) { this.SetText1("Value: " + this.i1.ToString()); this.i1++; Thread.Sleep(1); } this.SetText1("Thread finished: " + this.i1.ToString()); } private void DoThread2() { while (this.Thread2Running) { this.SetText2("Value: " + this.i2.ToString()); this.i2++; Thread.Sleep(1); } this.SetText2("Thread finished: " + this.i2.ToString()); } private void SetText1(string text) { if (this.Thread1Running && this.Thread1 != null) { if (this.label_thread1.InvokeRequired) { SetTextCallback1 d1 = new SetTextCallback1(this.SetText1); this.label_thread1.Invoke(d1, new object[] { text }); } else { label_thread1.Text = text; } } } private void SetText2(string text) { if (this.Thread2Running && this.Thread2 != null) { if (this.label_thread2.InvokeRequired) { SetTextCallback2 d2 = new SetTextCallback2(this.SetText2); this.label_thread2.Invoke(d2, new object[] { text }); } else { label_thread2.Text = text; } } } private void button1_Click(object sender, EventArgs e) { StartThread1(); this.button1.Text = "Running thread 1"; this.button3.Enabled = !(this.button1.Enabled = false); } private void button2_Click(object sender, EventArgs e) { StartThread2(); this.button2.Text = "Running thread 2"; this.button4.Enabled = !(this.button2.Enabled = false); } private void button3_Click(object sender, EventArgs e) { this.EndThread1(); this.button1.Text = "Start thread 1"; this.button3.Enabled = !(this.button1.Enabled = true); } private void button4_Click(object sender, EventArgs e) { this.EndThread2(); this.button2.Text = "Start thread 2"; this.button4.Enabled = !(this.button2.Enabled = true); } } }
Zdrojové súbory sú k dispozícii v prílohe. Aplikáciu preložte (build) a spustite a môžete si skúsť, ako samostatne a nezávisle pracujú vlákna a vy môžete hýbať a pracovať nezávisle s formulárom.
Program bol navrhnutý v prostredí: Microsoft Visual Studio 2010 Ultimate, Microsoft .NET Framework Version 4.0.30319 SP1Rel
Predpokladám základné znalosti s prácou objektami a prácou vo Visual C#.
S pozdravom.
AB