Laden...

Multi Thread Bitmap

Erstellt von tomschrot vor 17 Jahren Letzter Beitrag vor 17 Jahren 2.154 Views
T
tomschrot Themenstarter:in
73 Beiträge seit 2004
vor 17 Jahren
Multi Thread Bitmap

Grüße,

auf einem Winfrom habe ich eine PictureBox, darin ein Bitmap
kann ich anzeigen, via SetPixel malen etc., klappt alles prima

jetzt kommts:

eigentlich möchte ich aber aus mehreren threads auf diese bitmap zeichnen, also thread1 oberer hälfte des bilds, thread2 unterer hälfte usw.

gibt immer eine ausnahme:

Eine nicht behandelte Ausnahme des Typs "System.InvalidOperationException" ist in System.Drawing.dll aufgetreten.

Zusätzliche Informationen: Das Objekt wird bereits an anderer Stelle verwendet.

gibts eine lösung dafür?

871 Beiträge seit 2005
vor 17 Jahren

Hallo,

ich hab dir mal ein einfaches beispiel zusammengehackt - es geht einfach darum, dass Du auf die Bitmap nur vom erzeugenden Thread aus zugreifen solltest und diese zugriffe auch synchronisieren musst.


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

namespace MultiBitmap
{
    public class Program : Form
    {
        private Bitmap m_Image;
        private object m_LockObject;
        private delegate void DrawStringCallback( string text, Point position, Color color );
        private bool m_Stop = false;

        public static void Main( string[] args )
        {
            Program p = new Program();
            Application.Run( p );
        }

        public Program()
        {
            m_LockObject = new object();
            this.Size = new Size( 640, 480 );

            PictureBox picBox = new PictureBox();
            picBox.Location = new Point( 0, 0 );
            picBox.Size = this.ClientSize;
            picBox.Anchor = ( AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top );

            m_Image = new Bitmap( picBox.Size.Width, picBox.Size.Height );
            picBox.Image = m_Image;
            this.Controls.Add( picBox );            

            Thread drawOne = new Thread( new ThreadStart( DrawThreadOne ));
            Thread drawTwo = new Thread( new ThreadStart( DrawThreadTwo ));

            drawOne.Start();
            drawTwo.Start();
        }

        protected override void OnClosing( System.ComponentModel.CancelEventArgs e )
        {
            m_Stop = true;
            base.OnClosing( e );
        }

        private void DrawThreadOne()
        {
            while( ! m_Stop )
            {
                DrawString( "Thread 1", new Point( 10, 10 ), Color.Green );
                Thread.Sleep( 1000 );
            }
        }

        private void DrawThreadTwo()
        {
            while( ! m_Stop )
            {
                DrawString( "Thread 2", new Point( 20, 20 ), Color.Red );
                Thread.Sleep( 1000 );
            }
        }

        private void DrawString( string text, Point position, Color color )
        {
            if( this.InvokeRequired )
            {
                this.Invoke( new DrawStringCallback( this.DrawString ), new object[] { text, position, color } );
            }
            else
            {
                lock( m_LockObject )
                {
                    Graphics g = Graphics.FromImage( m_Image );
                    g.DrawString( text, new Font( FontFamily.GenericSansSerif, 10.0f ), new SolidBrush( color ), new PointF( position.X, position.Y ));
                    g.Dispose();
                }
            }
        }
    }
}

Grüsse, Egon

T
tomschrot Themenstarter:in
73 Beiträge seit 2004
vor 17 Jahren

@ egrath:

danke!

habs probiert geht aber nicht....!!!! 🙁

jetzt ist es zwar möglich beide threads ohne fehler zu starten dennoch wird erst der eine und wenn fertig der andere ausgeführt. .....???

da bei mir die pixel uu. recht lange dauern und ich einen dual core habe wärs halt schön auch beide cpus zu nutzen...

so wies jetzt geht bringts nix weil jeder thread in der warteschlange landet.

was nun?

871 Beiträge seit 2005
vor 17 Jahren

Hallo,

Wenn es sich um längerdauernde Zeichenoperationen handelt solltest Du diese auch nicht innerhalb des gelockten Bereichs durchführen. Eine möglichkeit dies zu bewerkestelligen wäre beispielsweise, dass jeder Thread eine eigene Bitmap Instanz hält, in diese zeichnet und erst wenn die Bitmaps dann zu einer verschmolzen werden sollen, werden diese per DrawImage in das Zielbitmap kopiert.

Für welches Anwendungsgebiet brauchst Du das eigentlich, vielleicht gibts auch andere schöne Lösungen dafür.

Grüsse, Egon

T
tomschrot Themenstarter:in
73 Beiträge seit 2004
vor 17 Jahren

@ egon:

ich locke eigentlich erst beim setzen des pixel!
have a look:


		private delegate void LoopHandle(LoopParameters p, Fractals.Mandelbrot m);
		
		private void ThreadLoop(object paras)
		{
			LoopParameters 		p = (LoopParameters)		(paras as object[])[0];
			Fractals.Mandelbrot m = (Fractals.Mandelbrot)	(paras as object[])[1];
				
			if(_Form.InvokeRequired)
				 _Form.Invoke(new LoopHandle(Loop), new object[]{p,m});
			else Loop(p,m);
		}
		
		private void Loop(LoopParameters p, Fractals.Mandelbrot m)
		{
			int		iterations;
			
			Color	color;
			
			double 	runX,
			runY;
			
			_Form.Text = string.Format("Thread {0}", p.BeginLine+1);
			
			runY = p.startY;
			for(int y=p.BeginLine; y<p.Height; y+=p.StepLine)
			{
				runX = p.startX;
				for(int x=0; x<p.Width; x++)
				{
					iterations = m.Iterate(runX, runY, p.MaxIterations);
					runX += p.stepX;
					
					color = Color.FromArgb( (iterations*((1<<11)-1)) );
					
					lock(_SyncRoot)
					{
						p.Image.SetPixel(x, y, color);
					}
				}
				runY -= p.stepY;
				p.Box.Refresh();
			}
		}


wobei ThreadLoop der einsprungspunkt je thread ist und jeweils die schleife startet.