• Добро пожаловать на сайт - Forumteam.wiki !

    Что бы просматривать темы форума необходимо зарегестрироваться или войти в свой аккаунт.

    Группа в телеграме (подпишитесь, что бы не потерять нас) - ForumTeam Chat [Подписатся]
    Связь с администратором - @ftmadmin

55. Многопоточность на примере и задание на дом.

Redman

<FORUMTEAM>
Команда форума
Регистрация
13.11.17
Сообщения
13.343
Реакции
8.367
Баллы
1.200
FTC
203¢
Практический пример на использование механизма многопоточности.
Данное приложение является учебным примером на использование механизма многопоточности в C# - приложениях.
Код:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;

namespace CSharpApplication.Threads
{
    // Пляшущие индикаторы
    class ProgressBarDance : Form
    {
        // Количество потоков
        const int ThreadsCount = 3;

        // Индикаторы
        ProgressBar [] pr = new ProgressBar[ThreadsCount];
        // Флажки для запуска/остановки потоков
        CheckBox [] bRun = new CheckBox[ThreadsCount];
        // Флажки для приостановки/возобновления потоков
        CheckBox [] bSuspend = new CheckBox[ThreadsCount];
        // Флажки для хранения состояния потоков
        bool [] ThreadsRun = new bool[ThreadsCount];
        // Массив делегатов (ссылаются на функцию - точку входа в поток)
        ThreadStart [] threadsstart;
        // Массив потоков
        Thread [] threads;

        static void Main()
        {
            // Запуск приложения
            Application.Run(new ProgressBarDance());
        }

        ProgressBarDance()
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.FormBorderStyle = FormBorderStyle.Fixed3D;
            this.ClientSize = new Size(350, 310);         

            this.Icon = new Icon(GetType(), "Ico.ico");
            this.Text = "Работа с потоками";

            // Инициализация элементов управления
            for(int i = 0; i < ThreadsCount; i++)
            {
                pr[i] = new ProgressBar();
                pr[i].Parent = this;
                pr[i].Location = new Point(10, 10 + i * 100);
                pr[i].ClientSize = new Size(this.ClientRectangle.Width - 20, 50);
                // Минимальное значение индикатора
                pr[i].Minimum = 0;
                // Максимальное значение индикатора
                pr[i].Maximum = 100;

                bRun[i] = new CheckBox();
                bRun[i].Parent = this;
                bRun[i].Location = new Point(10, 10 + i * 100 + 65);
                bRun[i].ClientSize = new Size(150, 20);
                bRun[i].Text = string.Format("Запустить {0}-й поток", i + 1);
   
                bSuspend[i] = new CheckBox();
                bSuspend[i].Parent = this;
                bSuspend[i].Location = new Point(170, 10 + i * 100 + 65);
                bSuspend[i].ClientSize = new Size(200, 20);
                bSuspend[i].Text = string.Format("Приостановить {0}-й поток", i + 1);
                bSuspend[i].Enabled = false;

                // Обработчик щелчков по CheckBox'ам
                bRun[i].Click += new EventHandler(OnCheckBoxClick);
                bSuspend[i].Click += new EventHandler(OnCheckBoxClick);
            }
        }

        // Потоковая функция
        private void WorkThread()
        {
            Random r = new Random();

            // Получаем индекс потока, который записан в его имени
            int index = Convert.ToInt32(Thread.CurrentThread.Name);

            // Пока флаг состояния потока утановлен
            while(ThreadsRun[index] == true)
            {
                // Выбираем случайное значение для позиции индикатора
                pr[index].Value = r.Next(100);
                // Усыпляем поток на случайный интервал времени
                Thread.Sleep(r.Next(50, 500));
            }
        }
       
        // Обработчик щелчка по CheckBox'ам
        private void OnCheckBoxClick(object sender, EventArgs e)
        {
            // Если щелкаем впервые
            if(threadsstart == null)
            {
                // Инициализируем массив делегатов
                threadsstart = new ThreadStart[]
                    {
                        new ThreadStart(WorkThread),
                        new ThreadStart(WorkThread),
                        new ThreadStart(WorkThread)
                    };

                threads = new Thread [ThreadsCount];
           
                // Инициализируем потоки
                for(int i = 0; i < ThreadsCount; i++)
                {
                    // Создаем поток
                    threads[i] = new Thread(threadsstart[i]);
                    // Даем ему имя (равное индексу)
                    threads[i].Name = string.Format("{0}", i);
                    // Указываем, что поток не запущен
                    ThreadsRun[i] = false;
                }
            }

            // Определяем активный элемент на форме (CheckBox)
            CheckBox check = (CheckBox)this.ActiveControl;
            // Ищем его индекс в массиве флажков запуска потоков
            int index = Array.IndexOf(bRun, check);
           
            // Нажат CheckBox из этого массива
            if(index != -1)
            {
                // Если галочка установлена
                if(check.Checked == true)
                {
                    // Указываем, что поток запущен
                    ThreadsRun[index] = true;
                    bRun[index].Text = string.Format("Остановить {0}-й поток", index + 1);
                    bSuspend[index].Enabled = true;
                    // Запуск потока
                    threads[index].Start();
                }
                else // Если галочка снята
                {
                    // Если поток находится в приостановленном состоянии
                    if(bSuspend[index].Checked == true)
                    {
                        // Возобновляем его работу
                        threads[index].Resume();
                        bSuspend[index].Checked = false;
                    }

                    // Можно прервать поток насильно, но при этом все
                    // несохраненные данные будут утеряны
                    // threads[index].Abort();


                    // Указываем, что поток заканчивает свою работу
                    ThreadsRun[index] = false;
                    // Ожидаем завершения потока
                    threads[index].Join();
                    // Снова инициализируем данный поток
                    threads[index] = new Thread(threadsstart[index]);   
                    pr[index].Value = 0;
                    bRun[index].Text = string.Format("Запустить {0}-й поток", index + 1);
                    bSuspend[index].Enabled = false;
                }
            }
            else
            {
                // Ищем индекс в массиве флажков приостановки потоков
                int sindex = Array.IndexOf(bSuspend, check);
                // Если данный поток не запущен
                if(ThreadsRun[sindex] == false)
                    return;
                // Если галочка утановлена
                if(check.Checked == true)
                {
                    // Приостанавливаем поток
                    threads[sindex].Suspend();
                    bSuspend[sindex].Text = string.Format("Возобновить {0}-й поток", sindex + 1);
                }
                else
                {
                    // Возобновляем работу потока
                    threads[sindex].Resume();
                    bSuspend[sindex].Text = string.Format("Приостановить {0}-й поток", sindex + 1);
                }
            }
        }

        // Обработчик закрытия формы
        protected override void OnClosed(EventArgs e)
        {
            // Перебираем массив потоков
            for(int i= 0; i < ThreadsCount; i++)
            {
                /*******************************************************/
                /* Первый способ остановки запущенных потоков
                /*******************************************************/
                // Если поток запущен
                if(ThreadsRun[i] == true)
                {
                    // Сбрасываем флаг состояния потока (остановка потока)
                    ThreadsRun[i] = false;
                    // Если поток был приостановлен
                    if(bSuspend[i].Checked == true)
                        // Возобновляем работу потока
                        threads[i].Resume();
                }
               
                /******************************************************/
                /* Второй способ остановки запущенных потоков
                /******************************************************/
                /*
                if(bSuspend[i].Checked == true)
                    // Возобновляем работу потока
                    threads[i].Resume();
                // "Грубая" остановка потока
                threads[i].Abort();
                */

                /******************************************************/
                /* Третий способ остановки запущенных потоков
                /******************************************************/
               
                // Перевод потоков в фоновый режим
                // threads[i].IsBackground = true;
            }
            base.OnClosed (e);
        }
    }
}

Домашнее задание
Реализовать приложение, в котором пользователь имеет возможность указывать маски файлов для поиска и набор путей, по которым эти файлы нужно искать (например, список логических дисков). Рекомендуем воспользоваться механизмом многопоточности.
 
Сверху Снизу