Передача графики между потоками с использованием семафоров и буферов в C # - PullRequest
1 голос
/ 08 марта 2012

Мой английский не очень хорош, написано очень просто, поэтому заранее извините ...

Я видел подобные вопросы, но не использовал графику.

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

Я путаюсь с природой буферов и семафоров, я думаю, но, читая их, я все равно не могу заставить их вести себя так, как я хочу ...

Система, когда она покидает первую панель, будет одновременно выделять точку во всех 4 WaitPanelThreads, а это не то, что мне нужно.

Я пытался просто добавить больше семафоров, но это не принесло пользы. Я построил свои собственные семафоры и буферы, чтобы попытаться понять, что они делают, но я не могу продолжить эту программу. Я потратил целую вечность, пытаясь заставить систему вести себя правильно, но я озадачен, если что-то из этого не имело особого смысла из-за моего английского, спросите, и я постараюсь сформулировать это лучше.

Ниже приведен весь код, который я написал для этого, я почти уверен, что проблема в том, где я создаю свой WaitPanelThreads. Любая помощь приветствуется, я пытаюсь научить себя этому.

Felix

РЕДАКТИРОВАТЬ: Я также должен прокомментировать, что приведенный ниже код будет работать, если вы добавите его в Visual Studio, вам может понадобиться включить две ссылки, если вы хотите посмотреть, как он настроен

using System;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;
using System.Collections;
using System.Data;
using System.Drawing;

public class Form1 : Form
{

    private Container components = null;
    private ButtonPanelThread p1;
    private Button btn1;
    private WaitPanelThread p2, p3, p4, p5;
    private Thread thread1, thread2, thread3, thread4, thread5;
    private Semaphore semaphore, semaphore1;
    private Buffer buffer, buffer1;
    private Thread semThread, semThread1;
    private Thread buffThread, buffThread1;
    private Panel pnl1, pnl2, pnl3, pnl4, pnl5;


    public Form1()
    {
        InitializeComponent();


        semaphore = new Semaphore();
        semaphore1 = new Semaphore();
        buffer = new Buffer();
        buffer1 = new Buffer();


        p1 = new ButtonPanelThread(new Point(40, 10),
                             30, true, pnl1,
                             Color.Blue,
                             semaphore,
                             buffer,
                             btn1);

        p2 = new WaitPanelThread(new Point(10, 10),
                             80, false, 2, pnl2,
                             Color.White,
                             semaphore,
                             buffer);

        p3 = new WaitPanelThread(new Point(10, 10),
                             77, false, 3, pnl3,
                             Color.White,
                             semaphore,
                             buffer);
        p4 = new WaitPanelThread(new Point(250, 10),
                             77, false, 4, pnl4,
                             Color.White,
                             semaphore,
                             buffer);
        p5 = new WaitPanelThread(new Point(10, 250),
                             77, false, 1, pnl5,
                             Color.White,
                             semaphore,
                             buffer);

        semThread = new Thread(new ThreadStart(semaphore.Start));
        semThread1 = new Thread(new ThreadStart(semaphore1.Start));
        buffThread = new Thread(new ThreadStart(buffer.Start));
        buffThread1 = new Thread(new ThreadStart(buffer1.Start));
        thread1 = new Thread(new ThreadStart(p1.Start));
        thread2 = new Thread(new ThreadStart(p2.Start));
        thread3 = new Thread(new ThreadStart(p3.Start));
        thread4 = new Thread(new ThreadStart(p4.Start));
        thread5 = new Thread(new ThreadStart(p5.Start));


        this.Closing += new CancelEventHandler(this.Form1_Closing);

        semThread.Start();
        semThread1.Start();
        buffThread.Start();
        buffThread1.Start();
        thread1.Start();
        thread2.Start();
        thread3.Start();
        thread4.Start();
        thread5.Start();

    }


    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (components != null)
                components.Dispose();
        }
        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        this.Text = "Circuit movements";
        this.Size = new System.Drawing.Size(900, 700);
        this.BackColor = Color.LightGray;

        this.pnl1 = new Panel();
        this.pnl1.Location = new Point(100, 100);
        this.pnl1.Size = new Size(260, 30);
        this.pnl1.BackColor = Color.White;

        this.btn1 = new Button();
        this.btn1.Size = new Size(30, 30);
        this.btn1.BackColor = Color.Pink;
        this.btn1.Location = new System.Drawing.Point(0, 0);


        this.pnl2 = new Panel();
        this.pnl2.Location = new Point(350, 100);
        this.pnl2.Size = new Size(260, 30);
        this.pnl2.BackColor = Color.White;

        this.pnl3 = new Panel();
        this.pnl3.Location = new Point(580, 100);
        this.pnl3.Size = new Size(30, 260);
        this.pnl3.BackColor = Color.White;

        this.pnl4 = new Panel();
        this.pnl4.Location = new Point(350, 360);
        this.pnl4.Size = new Size(260, 30);
        this.pnl4.BackColor = Color.White;

        this.pnl5 = new Panel();
        this.pnl5.Location = new Point(350, 100);
        this.pnl5.Size = new Size(30, 260);
        this.pnl5.BackColor = Color.White;

        this.Controls.Add(pnl1);
        this.Controls.Add(pnl2);
        this.Controls.Add(pnl3);
        this.Controls.Add(pnl4);
        this.Controls.Add(pnl5);
        this.pnl1.Controls.Add(btn1);

        // Wire Closing event.      
        this.Closing += new CancelEventHandler(this.Form1_Closing);
    }

    private void Form1_Closing(object sender, CancelEventArgs e)
    {
        // Environment is a System class.
        // Kill off all threads on exit.
        Environment.Exit(Environment.ExitCode);
    }


}// end class form1


public class Buffer
{
    private Color planeColor;
    private bool empty = true;

    public void Read(ref Color planeColor)
    {
        lock (this)
        {
            // Check whether the buffer is empty.
            if (empty)
                Monitor.Wait(this);
            empty = true;
            planeColor = this.planeColor;
            Monitor.Pulse(this);
        }
    }

    public void Write(Color planeColor)
    {
        lock (this)
        {
            // Check whether the buffer is full.
            if (!empty)
                Monitor.Wait(this);
            empty = false;
            this.planeColor = planeColor;
            Monitor.Pulse(this);
        }
    }

    public void Start()
    {
    }

}// end class Buffer

public class Semaphore
{
    private int count = 0;

    public void Wait()
    {
        lock (this)
        {
            while (count == 0)
                Monitor.Wait(this);
            count = 0;
        }
    }

    public void Signal()
    {
        lock (this)
        {
            count = 1;
            Monitor.Pulse(this);
        }
    }

    public void Start()
    {
    }

}// end class Semaphore

public class ButtonPanelThread
{
    private Point origin;
    private int delay;
    private Panel panel;
    private bool westEast;
    private Color colour;
    private Point plane;
    private int xDelta;
    private int yDelta;
    private Semaphore semaphore;
    private Buffer buffer;
    private Button btn;
    private bool locked = true;



    public ButtonPanelThread(Point origin,
                             int delay,
                             bool westEast,
                             Panel panel,
                             Color colour,
                             Semaphore semaphore,
                             Buffer buffer,
                             Button btn)
    {
        this.origin = origin;
        this.delay = delay;
        this.westEast = westEast;
        this.panel = panel;
        this.colour = colour;
        this.plane = origin;
        this.panel.Paint += new PaintEventHandler(this.panel_Paint);
        this.xDelta = westEast ? +10 : -10;
        this.yDelta = 0;
        this.semaphore = semaphore;
        this.buffer = buffer;
        this.btn = btn;
        this.btn.Click += new System.
                              EventHandler(this.btn_Click);


    }

    private void btn_Click(object sender,
                           System.EventArgs e)
    {
        locked = !locked;
        this.btn.BackColor = locked ? Color.Pink : Color.LightGreen;
        lock (this)
        {
            if (!locked)
                Monitor.Pulse(this);
        }
    }

    public void Start()
    {
        Color signal = Color.Red;
        Thread.Sleep(delay);


        for (int k = 1; k <= 30; k++)
        {
            this.zeroPlane();
            panel.Invalidate();
            lock (this)
            {
                while (locked)
                {
                    Monitor.Wait(this);
                }
            }
            for (int i = 1; i <= 20; i++)
            {
                this.movePlane(xDelta, yDelta);
                Thread.Sleep(delay);
                panel.Invalidate();
            }
            semaphore.Wait();
            buffer.Write(this.colour);
        }
        this.colour = Color.Gray;
        panel.Invalidate();
    }

    private void zeroPlane()
    {
        plane.X = origin.X;
        plane.Y = origin.Y;
    }

    private void movePlane(int xDelta, int yDelta)
    {
        plane.X += xDelta; plane.Y += yDelta;
    }

    private void panel_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;

        SolidBrush brush = new SolidBrush(colour);
        g.FillRectangle(brush, plane.X, plane.Y, 10, 10);

        brush.Dispose();    //  Dispose graphics resources. 
        g.Dispose();        //  
    }
}// end class ButtonPanelThread

public class WaitPanelThread
{
    private Point origin;
    private int delay;
    private Panel panel;
    private bool westEast;
    private int dir;
    /*
     * dir options:
     * 1 - north;
     * 2 - east;
     * 3 - south;
     * 4 - west.
     */
    private Color colour;
    private Point plane;
    private int xDelta;
    private int yDelta;
    private Semaphore semaphore;
    private Buffer buffer;


    public WaitPanelThread(Point origin,
                       int delay,
                       bool westEast,
                       int dir,
                       Panel panel,
                       Color colour,
                       Semaphore sem,
                       Buffer buff)
    {
        this.origin = origin;
        this.delay = delay;
        this.westEast = westEast;
        this.dir = dir;
        this.panel = panel;
        this.colour = colour;
        this.plane = origin;
        this.panel.Paint += new PaintEventHandler(this.panel_Paint);

        switch (dir)
        {
            case 1:
                this.xDelta = 0;
                this.yDelta = -10;
                break;
            case 2:
                this.xDelta = +10;
                this.yDelta = 0;
                break;
            case 3:
                this.xDelta = 0;
                this.yDelta = +10;
                break;
            case 4:
                this.xDelta = -10;
                this.yDelta = 0;
                break;
        }
        this.semaphore = sem;
        this.buffer = buff;

    }

    public void Start()
    {
        this.colour = Color.White;
        for (int k = 1; k <= 40; k++)
        {
            semaphore.Signal();
            this.zeroPlane();

            buffer.Read(ref this.colour);

            for (int i = 1; i <= 20; i++)
            {

                panel.Invalidate();
                this.movePlane(xDelta, yDelta);
                Thread.Sleep(delay);

            }
            this.colour = Color.White;
            panel.Invalidate();


        }
        this.colour = Color.Gray;
        panel.Invalidate();
    }

    private void zeroPlane()
    {
        plane.X = origin.X;
        plane.Y = origin.Y;
    }

    private void movePlane(int xDelta, int yDelta)
    {
        plane.X += xDelta; plane.Y += yDelta;
    }

    private void panel_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        SolidBrush brush = new SolidBrush(colour);
        if (dir == 2 || dir == 4)
        {
            g.FillRectangle(brush, plane.X, plane.Y, 10, 10);
        }
        if (dir == 1 || dir == 3)
        {
            g.FillRectangle(brush, plane.X, plane.Y, 10, 10);
        }

        brush.Dispose();    //  Dispose graphics resources. 
        g.Dispose();        //  
    }
}// end class WaitPanelThread

public class Driver
{
    public static void Main()//
    {

        Application.Run(new Form1());
    }
}// end class TheOne
...