Problem z uruchomieniem kilku wątków

0

Witam wszystkich!

Kod który znajduje się poniżej jest raczej prosty i wiadomo o co w nim chodzi. Problem polega na tym, że po kilkakrotnym naduszeniu przycisku 'A', a co za tym idzie uruchomieniu kilku (ok. 4, 5 - nie ma reguły) nowych wątków program zawiesza się i wyrzuca błąd "Wystąpił problem z aplikacją WindowsFormsApplication1 i zostanie ona zamknięta. Przepraszamy za kłopoty.". I tyle.

Pomocy [!!!] Dlaczego tak się dzieje [!!!] [!!!] [!!!]

klasa Form1:

    public partial class Form1 : Form
    {
        public Graphics g;
        
        public Form1()
        {
            InitializeComponent();

            pictureBox1.Image = new Bitmap(461, 358);
            g = Graphics.FromImage(pictureBox1.Image);

            
            
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.A)
            {
                D d = new D(g, pictureBox1);

                ThreadStart ts = new ThreadStart(d.f);

                Thread t = new Thread(ts);

                t.Start();

            }
        }
    }

klasa D:

    class D : Form1
    {
        
        public D(Graphics _g, PictureBox _p)
        {
            this.g = _g;
            this.pictureBox1 = _p;
        }
        
        public void f()
        {
            while (true)
            {

                Random a = new Random();

                a.Next(3);
                int wspx;

                if (a.Next(3) == 1)
                    wspx = 10;
                else
                    wspx = 50;

                this.g.FillRectangle(Brushes.Black, wspx, 10, 20, 20);

                this.pictureBox1.Refresh();


                Thread.Sleep(100);
            }
        }
    }
0

Może dlatego, że kilka wątków jednocześnie próbuje rysować po tym samym obiekcie graficznym...

W ogóle to po co twoja klasa D dziedziczy po Form ?

0

A co musiałbym zrobić, aby wątki nie rysowały na raz. Co musiałbym zrobić, aby w ogóle to naprawić?

0
orzech123 napisał(a)

A co musiałbym zrobić, aby wątki nie rysowały na raz. Co musiałbym zrobić, aby w ogóle to naprawić?

Zsynchronizować je.

0

Poniżej wklejam przykład synchronizacji dla Twojego przypadku. Nie jest to jedyne rozwiązanie i chyba nie najlepsze :-)

public partial class Form1 : Form
    {
        private static readonly Object _synchronize = new Object();
        private Graphics _graphics;
        private Brush[] _brushes = new Brush[] { Brushes.Blue, Brushes.Red, Brushes.Black, Brushes.White, Brushes.Yellow };
        private int _index = 0;
        public Form1()
        {
            InitializeComponent();
            pictureBox.Image = new Bitmap(pictureBox.Width, pictureBox.Height);
            _graphics = Graphics.FromImage(pictureBox.Image);
        }

        private void ButtonStartClick(object sender, EventArgs e)
        {
            Context.DoWork = true;
            _index = _index % _brushes.Length;
            Thread thread = new Thread(new ParameterizedThreadStart(DrawManager.Draw));
            thread.Start(new Context(_graphics, pictureBox, _synchronize, _brushes[_index]));
            _index++;
        }

        private void ButtonStopClick(object sender, EventArgs e)
        {
            Context.DoWork = false;
        }
    }

    public static class DrawManager
    {
        public static void Draw(Object param)
        {
            if (param is Context)
            {
                Context context = param as Context;
                Random random = new Random(Environment.TickCount);
                const int size = 10;
                while (Context.DoWork)
                {
                    lock (context.Synchronize)
                    {
                        context.GraphicsInstance.FillRectangle(
                            context.BrushInstance, 
                            random.Next(context.Control.Width), 
                            random.Next(context.Control.Height), 
                            size, size);
                        context.Control.Refresh();
                    }
                    Thread.Sleep(100);
                }
            }
        }
    }

    class Context
    {
        public static bool DoWork = true;
        private Graphics _graphics;
        private PictureBox _pictureBox;
        private Object _synchronize;
        private Brush _brush;

        public Context(Graphics graphics, PictureBox pictureBox, Object synchronize, Brush brush)
        {
            _brush = brush;
            _graphics = graphics;
            _pictureBox = pictureBox;
            _synchronize = synchronize;
        }

        public Graphics GraphicsInstance
        {
            get { return _graphics; }
        }

        public PictureBox Control
        {
            get { return _pictureBox; }
        }

        public Object Synchronize
        {
            get { return _synchronize; }
        }

        public Brush BrushInstance
        {
            get { return _brush; }
        }
    }

Wrzuć na formę dwa przyciski i jeden PictureBox - wszystko powinno działać. Do synchronizacji użyłem słowa kluczowego lock. Poczytaj o nim.

0

Nie byłoby prościej gdyby każdy wątek wywoływał funkcję Invoke() I w ten sposób rysował?
Chciałem podać przykład, ale w notatniku nie idzie mi programowanie, a właśnie jestem na wakacjach bez środowiska.

1 użytkowników online, w tym zalogowanych: 0, gości: 1