C# хэлний олон урсгал буюу Multithreading ухагдхууны талаар аьч үзье. Сэдэв өргөн хүрээтэй, нарийн, хүндэвтэр учраас нилээд хэдэн хичээлийг хамран судлах болно. Multithreading ухагдхууныг практик ажилд ихээр тохиолддог энгийн жишээнээс эхлэн авч үзье. Бидэнд удаан хугацаанд биелэгдэх ажиллагааг эхлүүлээд түүний явцыг хянах хэрэгтэй боллоо гэе.
Үүнийг загварчлахын тулд прогресс бар, Эхлэх, Зогсоох гэсэн хоёр товч бүхий энгийн форм үүсгэе.
Эхлэх товч ажиллагааг эхлүүлнэ гэдэг нь ойлгомжтой. Харин Зогсоох товч ажиллагааг дуусаагүй байхад зогсоох үүрэгтэй. C# дээр програм хэрхэн үүсгэх, формыг яаж зурахыг та өөрөө сайн мэдэж байгаа гэж бодож байна. Програмын үндсэн класс бол
using System;
using System.Threading;
namespace MultiThread
{
class Worker
{
private bool _cancelled = false;
public void Cancel()
{
_cancelled = true;
}
public void Work()
{
for (int i = 0; i <= 99; i++)
{
if (_cancelled)
break;
Thread.Sleep(50);
ProcessChanged(i);
}
WorkCompleted(_cancelled);
}
public event Action<int> ProcessChanged;
public event Action<bool> WorkCompleted;
}
}
код бүхий ямар нэгэн удаан хугацаанд биелэгдэх ажиллагааг үзүүлэх Worker юм. Класс хэсэг элементээс бүрдэнэ. Эхнийх нь бол ажиллагааг цуцлагдсан эсэхийг заах private хэлбэрийн _cancelled талбар. Талбарт утга олгох Cancel нээлттэй арга удаан хугацаанд биелэгдэх ажиллагааг програмаас зогсоох командыг өгөхөд _cancelled талбарт true утгыг өгөх юм. Классын үндсэн арга Work урт хугаацаатай хийгдэх ажиллагааг төлөөлнө. Арга ердийн цикл эхлүүлээд цикл дотроо _cancelled талбарыг шалгана. Хэрвээ талбарын утга true буюу ажиллагааг цуцалсан бол циклийн ажиллагааг тэр дор нь break командаар зогсооно. Цааш Thread.Sleep(50) командаар бид хийгдэж байгааг ажиллагааг харуулж байгаа хэрэг. Энд урсгал эсхүл багцтай /thread/ ажилладаг эхний аргатай танилцаж байгаа. Sleep арга тухайн үед ажиллаж байгаа урсгалыг заагдсан тооны миллисекундээр зогсоодог. Кодод бид ажиллагааны логикийг төлөөлүүлэн thread -ыг 50 миллисекунд зогсоосон хэрэг. Бодит програмд үүний оронд ямар нэгэн үйлдлийг хийх нь ойлгомжтой. Програм тодорхой үйлдлийг хийсний дараа үйл явцыг ажиглахаар /сонсох/ бүртгүүлсэн бүртгүүлэгчдэд мэдэгдэхийн тулд зохих ажиллагааны үйл явцыг дуудах хэрэгтэй. Циклээс гараагүй учраас ажиллагаа нэг алхамаар урагшилсанг мэдэгдэхийн тулд ProcessChanged үйл явцад циклийн тоолуурыг дамжуулан дуудна. Цикл break командаар эсхүл ердийн явцаараа дууссан эсэхээс үл хамааран WorkCompleted үйл явцад бүртгүүлсэн бүх бүртгүүлэгчдэд ажиллагаа ердийн эсхүл цуцлагдсанг мэдэгдэхийн тулд түүнд _cancelled талбарын утгыг дамжуулан дуудна. Классын төгсгөлд үйл ажиллагааны явцыг ажиглагчдад мэдээллэх ProcessChanged, WorkCompleted хоёр үйл явцыг /event/ зарласан. ProcessChanged үйл явц ажиллагаа ямар нэгэн байдлаар урагшилсанг харин WorkCompleted нь ажиллагаа дууссанг илтгэнэ. Үндсэн классын ажиллагааны логик энгийн учраас таныг ойлгосон гэж үзээд програмын формын кодыг
namespace MultiThread
{
public partial class MainForm : Form
{
private Worker _worker;
public MainForm()
{
InitializeComponent();
butStart.Click += butStart_Click;
butStop.Click += butStop_Click;
}
private void butStart_Click(object sender, EventArgs e)
{
_worker = new Worker();
_worker.ProcessChanged += _worker_ProcessChanged;
_worker.WorkCompleted += _worker_WorkCompleted;
butStart.Enabled = false;
_worker.Work();
}
private void _worker_ProcessChanged(int progress)
{
progressBar.Value = progress;
}
private void _worker_WorkCompleted(bool cancelled)
{
string message = cancelled ? "Ажиллагаа цуцлагдсан" : "Ажиллагаа дууссан";
MessageBox.Show(message);
butStart.Enabled = true;
}
private void butStop_Click(object sender, EventArgs e)
{
if (_worker != null)
worker.Cancel();
}
}
}
харцгаая. Эхлээд програмын бүх ажиллагаа нэг багцад /thread/ явагдах синхрон үйл ажиллагааг авч үзье. Формд үндсэн Worker класс төрлийн _worker хувьсагчийг зарласан. MainForm аргад формын Эхлэх, Зогсоох хоёр товчийг дарах үйл явцад бүртгүүлсэн. Үндсэн ажиллагаа butStart_Click аргад явагдана. Аргад Worker классын хувийг /обьект/ үүсгээд түүний ProcessChanged, WorkCompleted үйл явцуудад бүртгүүлнэ. Дараа нь Эхлэх товчийг дарсны дараа хэрэглэгч түүнийг форм дээрээс дахин дахин даруулахгүйн тулд butStart.Enabled = false; гэж идэвхигүй болгоод Worker классын Work аргыг дуудан ажиллагааг эхлүүлнэ. Worker классын үйл явцуудын боловсруулагчид юу хийгдэх вэ? WorkCompleted үйл явц Worker классын ажиллагаа дууссаны дараа үүснэ. Бид ажиллагааг цуцалсан эсэх cancelled хувьсагчийн утга true байвал Ажиллагаа цуцлагдсан харин утга false байвал Ажиллагаа дууссан гэсэн мэдээллийг үзүүлнэ. Үүгээр таны програмын ажиллагааны төлвөөс хамааран ямар ажиллагааг хийхийг харуулах гэсэн юм. Сургалтын жишээнд бид энгийн байлгах үүднээс текстийг дэлгэц дээр харуулаад хэрэглэгч ажиллагааг дахин явуулах боломжийг хангах зорилгоор Эхлэх товчийг идэвхитэй болгосон. ProcessChanged үйл явцын боловсруулагчид прогрес барын утганд түүнд дамжин ирсэн параметрийн утгыг олгосон. Зогсоох товчийг дарахад butStop_Click арга дуудагдах бөгөөд Worker классын хувь /обьект/ _worker үүссэн байвал түүний Cancel аргыг дуудна. Кодыг ажлуулаад Эхлэх товчийг дарвал
ажиллагаа явагдаж байгааг прогресс бар харуулах боловч бид формыг удирдаж чадахгүй. Хэдийгээр Зогсоох товч идэвхитэй байгаа ч түүн дээр даралт хийх боломжгүй. Програм синхрон горимд буюу форм, ажиллагааны процесс хоёр нэг багцад /thread/ ажиллаж байхад үндсэн процесс форм дээрх ямар нэгэн үйлдлийг бүрэн хаадаг. Өөрөөр хэлбэл хэрэглэгчийн форм дээр хийсэн үйлдлийг ердөө хүлээн авахгүй. Яагаад гэвэл Эхлэх товчийг даран ажиллагааг эхлүүлсний дараа бүх нөөцийг тухайн ажиллагаанд өгөөд график интерфейст юу ч үлдээгүйтэй холбоотой. Иймээс Эхлэх товчийг даран эхлүүлж буй ажиллагааг тусдаа урсгалд /thread/ явуулах хэрэгтэй гэсэн дүгнэлтэд хүрнэ.
Дараагийн хичээлүүдэд олон урсгалыг үүсгэн удирдах аргуудын талаар дэлгэрэнгүй авч үзэх болно.