Click here to Skip to main content
15,886,199 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
hello every body,
i have a small project, in which i am using Two Threads, and a method to draw circle on an image. when it starts so after some time it gives the error message object is currently in use elsewhere. sample of code is been give blow please, if anyone could give me some guidelines or some idea please.

C#
 private delegate void DrawCircleDelegate(Point pp, Bitmap r);
        public void DrawCircle(Point p, Bitmap rate)
        {
            if (InvokeRequired)
            {
                DrawCircleDelegate drwCircle = new DrawCircleDelegate((pp,r)=> DrawCircle(p,rate));
                this.BeginInvoke(drwCircle, new object[] { p,rate });
            }
            // utilObject.StateOccure += new SimUtil.InvalidState(utilObject_StateOccure); // Event handler , to handle invalid states
            Bitmap tempbitmap = (Bitmap)testImage.Clone();
            Graphics g = Graphics.FromImage(tempbitmap);

            if (rate== null )
                g.FillEllipse(Brushes.Green, p.X - 15, p.Y - 15, 30, 30);            
            else 
                g.DrawImage(rate, p.X - 15, p.Y - 15, 30, 30);

            pictureBox1.Image = tempbitmap;

        }
private void frmTwoThreads_Load(object sender, EventArgs e)
        {
            testImage = new Bitmap(@"D:\Practice_Projects\TestPic.png");
            rnd = new Random(DateTime.Now.Second);
            findNextThread = new Thread(FindNext);
            findNextThread.Name = " Find Thread";

        }
private void btnStarSimulator_Click(object sender, EventArgs e)
        {
            utilObject = new SimUtil();
            //rnd = new Random(DateTime.Now.Second);
           // List<Cell> gridCell = new List<Cell>();
            myGrid = new Grid(row, col, new Point(10, 10), new Point(460, 440));

            for (int clNo = 1; clNo <= myGrid.TotalCells; clNo++)
            {
                Cell tempCell = new Cell(clNo, col, row, myGrid.InitialPoint, myGrid.GridSize);
                myGrid.Cells.Add(tempCell);
            }
            testImage = myGrid.DrawGridOnBitmap(testImage, myGrid.InitialPoint, myGrid.EndPoint);
            pictureBox1.Image = testImage;
            DrawCircle(Get_CellCenterPoint(startCell),null);          


            findNextThread.Start();
        }
  public void FindNext()
        {

            while (true)
            {

                //moveCircleDelegate mcircle = moveCircle;               
                Point fromCellPoint;
                Point toCellPoint;
                int nextLocation = utilObject.SelectNextCell(startCell, rnd);
                while (nextLocation  <= 0 || nextLocation  > 100)
                {
                    string s1 = startCell.ToString() + " , " + nextLocation.ToString();
                    this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(s1); });  
                    nextLocation = utilObject.SelectNextCell(startCell, rnd);
                }
                              
                    fromCellPoint = Get_CellCenterPoint(startCell);
                    toCellPoint = Get_CellCenterPoint(nextLocation);
                    string s = startCell.ToString() + " , " + nextLocation.ToString() ;
                    this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(s); });             
                     moveCircleThread = new Thread(() => moveCircle(fromCellPoint, toCellPoint, 100));
                     moveCircleThread.Start();
                     moveCircleThread.Join();
                     startCell = nextLocation;
            }
        }
Posted
Updated 13-Jan-22 3:11am
Comments
agent_kruger 28-Nov-13 6:50am    
in which line do you recieve the error?
Muhammad Tufail 1979 28-Nov-13 6:54am    
thank you so much on your reply,
in the method DrawCircle, i am running this at the moment on my computer and i got again this error, it is exactly at
Bitmap tempbitmap = (Bitmap)testImage.clone();
while previously i got at
g.DrawImage( rate,p.x-15,p.y-15,30,30);
thanks once again

Images in GDI+ are not thread safe. What it means, basically - you cannot use one image from 2 threads simultaneously without some additional changes to your code.
Look at following pseudo code:

C#
public void SetPixels()
{
    var bmp = new Bitmap("Some image"); //Omitted using(), which is often mandatory
    var t = new Task(() => { for (int i = 0; i < 1000000; i++) {  
        bmp.SetPixel(0, 1, Color.Black); } });
    var t2 = new Task(() => { for (int i = 0; i < 1000000; i++) { 
        bmp.SetPixel(0, 1, Color.Black); } });
    t.Start();
    t2.Start();
    //Omitted wait for completion
}


At some moment here you will have "InvalidOperationException", which you described, since 2 different threads are setting colors of pixel in one image at same time.
You have to make lock each time, before you accessing to you bitmap.
On class level, declare variable
C#
private object _locker = new object();

And, in pseudo code, similar construction, as above, but which will execute without exceptions:
C#
public void SetPixels()
{
    var bmp = new Bitmap("Some image"); //Omitted using(), which is often mandatory
    var t = new Task(() => { for (int i = 0; i < 1000000; i++) 
        { lock (_locker) { bmp.SetPixel(0, 1, Color.Black); } } });
    var t2 = new Task(() => { for (int i = 0; i < 1000000; i++) 
        { lock (_locker) { bmp.SetPixel(0, 1, Color.Black); } } });
    t.Start();
    t2.Start();
    //Omitted wait for completion
}


lock
is built-in C# language construction; you can find info about it on MSDN.
 
Share this answer
 
v5
Comments
Muhammad Tufail 1979 28-Nov-13 7:35am    
thank you so much, do i need something else with lock?? and please could you tell me that either it will effect my code or running time please?
i tried your idea and now its working good.
thank you so much
Dmytro Bogachev 28-Nov-13 7:47am    
Threading itself and locking in particular indeed affects performance, decreasing it. But threading, from other side, makes your solution scalable and responsive. Sometimes you can rework your solution to work without locks, but sometimes, as in your case, you must lock objects to make solution work correctly (or to make them work at all). While lock is in affect, other threads cannot access locked sections of your code, so they will be blocked. Anyway, threading is topic for some academic book, not for small response)
Muhammad Tufail 1979 28-Nov-13 7:50am    
thank you so much for your explanation.
happy from your comments.
BillWoodruff 28-Nov-13 17:28pm    
+5 Excellent answer.
try using

Bitmap tempbitmap = (Bitmap)testImage;
 
Share this answer
 
Comments
Muhammad Tufail 1979 28-Nov-13 7:03am    
okay thank you i am going toward it now. some time id does not give error even for long long time, while some time gives error after short time of starting .
i don't know whats the problem.
Muhammad Tufail 1979 28-Nov-13 7:07am    
okay i did apply the above, now as i run the project so at the same time i am getting that error
Muhammad Tufail 1979 28-Nov-13 7:14am    
i never got this error when i was running this program on my office machine. but when i run it at my laptop so it give me this error
To avoid multiple threads accessing an image object I recommend always cloning the image and make sure each thread is working with its own clone.

Thread1_Img = MasterImage.Clone
Thread2_Img = MasterImage.Clone


This way each image is independent. This approach uses more memory, but is a safe way to work with images in a multi-threaded environment.

You should make sure you are cloning the image before handing it off to any new threads - otherwise it's too late. You cannot safely clone an image once another thread begins using it.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900