title: Transferring graphics between threads using semaphores and buffers in C#
body: <p>My english isn't very good, its very simple written so sorry in advance...</p>
  
  <p>I have seen similar questions to this but not using graphics.</p>
  
  <p>What I am trying to do is set up a simple circuit display, where a dot starts at the ButtonPanel, which whilst the button is clicked and green, will release more dots, I have used semaphores and buffers to control whether it goes into the next panel, the idea is the dot will do a circuit around the panels (in a clockwise motion) until the (for now) hard-coded limit makes the origin stop sending out dots.</p>
  
  <p>I am confused with the nature of buffers and semaphores I guess, but as much reading as I have done on them, I still fail to get it to behave how I want...</p>
  
  <p>The system when it leaves the first panel, will set off a dot in all 4 WaitPanelThreads at the same time, which is not what I want.</p>
  
  <p>I have tried just adding more semaphores but this doesn't do any good. I built my own semaphores and buffers to try and understand what they are doing but I am unable to proceed with this program. I have spent ages trying to get the system to behave correctly but I am stumped, if any of this didn't make much sense because of my english, ask and I will try to phrase it better.</p>
  
  <p>Below is all the code I am written for this, I am pretty sure the problem is where I construct my WaitPanelThreads. Any assistance is appreciated, I'm trying to teach myself this.</p>
  
  <p>Felix</p>
  
  <p>EDIT: I must also comment that the below code will all work if you slam it into visual studio, you may need to include two references if you want to see how it is set up</p>
  
  <pre><code>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 &lt;= 30; k++)
          {
              this.zeroPlane();
              panel.Invalidate();
              lock (this)
              {
                  while (locked)
                  {
                      Monitor.Wait(this);
                  }
              }
              for (int i = 1; i &lt;= 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 &lt;= 40; k++)
          {
              semaphore.Signal();
              this.zeroPlane();
  
              buffer.Read(ref this.colour);
  
              for (int i = 1; i &lt;= 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
  </code></pre>