Биллиард. Пример многопоточного приложения

Постановка задачи приведена в статье Движение шара на биллиардном столе. Там для простоты было рассмотрено однопоточное приложение, основанное на таймерном прерывании. Этот пример — анонс статей и примеров про параллельное программирование, в данном случае — многопоточное приложение.

Решение

На форме поместите кнопку button1. Класс Shar похож на аналогичный класс в ранее рассмотренном примере:

using System;
using System.Drawing;
using System.Threading;

namespace MultyThreadBiliard
{
    public class Shar
    {
        Point p;    // позиция
        Color c;    // цвет
        Point v;    // скорости
        int d;      // диаметр
        int n;      // число тактов
        public Shar()
        {
            Random r = new Random();
            // диаметр
            d = r.Next(20, 30);
            // позиция
            int q = r.Next(10);
            Thread.Sleep(q);
            r.Next();   
            p.X = r.Next(d, Form1.ActiveForm.Width-d);
            p.Y = r.Next(d, Form1.ActiveForm.Height-d);
            // цвет
            c = RandomColor(r.Next(1000));
            // скорости
            q = r.Next(12);
            Thread.Sleep(q);
            r.Next();
            v.X = r.Next(30) - 15;
            v.Y = r.Next(40) - 20;
            // начальное число
            n = 0;
        }
        // задание цвета
        public Color RandomColor(int rch)      // rch - случайное число
        {
            int r, g, b;
            byte[] bytes = new byte[3];        // массив 3 цветов
            Random rnd = new Random(rch);
            rnd.NextBytes(bytes);             // генерация в массив 
            r = Convert.ToInt16(bytes[0]);
            g = Convert.ToInt16(bytes[1]);
            b = Convert.ToInt16(bytes[2]);
            return Color.FromArgb(r, g, b);     // возврат цвета 
        }
        // движение объекта на плоскости
        public void Movie()
        {
            SolidBrush brush; 
            while (n < Form1.N_step)    // Выполнить N_step перемещений
            {
                lock (Form1.locker)     // замок
                {
                    n++;
                    // стирание
                    brush = new SolidBrush(Form1.ActiveForm.BackColor); 
                    Form1.g.FillEllipse(brush, p.X-1, p.Y-1, d+2, d+2);
                    // новая позиция
                    if ((p.X < 0) || (p.X >= Form1.ActiveForm.Width - d))
                        v.X = - v.X;                     
                    if ((p.Y < 0) || (p.Y >= Form1.ActiveForm.Height - d))
                        v.Y = - v.Y;
                    p.X += v.X;
                    p.Y += v.Y;
                    // новое рисование шаров
                    brush = new SolidBrush(c);
                    Form1.g.FillEllipse(brush, p.X, p.Y, d, d);
                    // задержка на 1 миллисекунду
                    Thread.Sleep(1);
                }                
            }
            Thread.Sleep(100);  // задержка потока
            Thread.CurrentThread.Abort();   // удаление           
        }
    }
}

И текст Form1.cs:

using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace MultyThreadBiliard
{
    public partial class Form1 : Form
    {
        public static int N = 16;   // число объектов
        public static int N_step = 200;    // шагов
        public Shar[] shars;    // массив объектов
        public static Graphics g;   // контекст
        public static object locker = new object(); // заглушка
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            g = this.CreateGraphics();  // инициализация
            BackColor = Color.Black;    // фон
        }

        // Старт процессов (потоков)
        private void Button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;    // закрыть
            button1.Visible = false;
            Shar[] shars = new Shar[N]; // ссылка на массив
            g.Clear(BackColor);         // очистка
            for (int k = 0; k < N; k++) // создание N потоков
            {
                lock (Form1.locker)     // замок
                {
                    shars[k] = new Shar();  // новый объект
                    Thread t = new Thread(shars[k].Movie);  // запуск
                    t.IsBackground = true;  // тип - фоновый
                    t.Start();              // старт
                }
            }
            int tau = 2 * N * N_step;   // расчет задержки
            Thread.Sleep(tau);          // задержка
            button1.Enabled = true;     // открыть
            button1.Visible = true;
        }    
    }
}

И все. Смотрим результат.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Пролистать наверх