Results 1 to 16 of 16

Thread: Baffling error in Background worker code

  1. #1

    Thread Starter
    New Member
    Join Date
    Dec 2021
    Posts
    6

    Baffling error in Background worker code

    Variables:
    Source and Destination are both bitmaps that are the same size
    hgt and wid are the height and width of the images minus 1

    Here's the background worker Code:
    Code:
    Private Sub BGWProcess_DoWork(sender As Object, e As DoWorkEventArgs) Handles BGWProcess.DoWork`
      For Y = 0 To hgt
     For X = 0 To wid
    If BGWProcess.CancellationPending Then Exit Sub
    Destination.SetPixel(X, Y, Source.GetPixel(X, Y)) 'Here is where it fails
     Next
    BGWProcess.ReportProgress(Y)
      Next
    End Sub
    
    Private Sub BGWProcess_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BGWProcess.ProgressChanged
    TxtProgress.Text = e.ProgressPercentage.ToString
    PictureBox1.Image = Destination
    End Sub
    The exception is "System.InvalidOperationException: Object is currently in use elsewhere."
    at the line "Destination.SetPixel(X, Y, Source.GetPixel(X, Y))
    There is nothing else going on that might be accessing any of the bitmaps or the PictureBox. Any ideas would be greatly appreciated.
    Last edited by Shaggy Hiker; Aug 31st, 2024 at 10:14 PM. Reason: Added CODE tags.

  2. #2
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: Baffling error in Background worker code

    Presumably this is a threading problem. Somewhere in all that a bitmap is probably accessed by multiple threads simultaneously.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Baffling error in Background worker code

    I agree with Niya. Take a look and, if necessary, show us everywhere else that those fields and the objects they refer to are used. Is one or the other displayed in a PictureBox? I'm not sure whether that would be enough to cause an issue but, if they are, try not doing that and see if the error remains.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  4. #4
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: Baffling error in Background worker code

    I don’t understand why you’re doing a pixel by pixel clone of an image in a background thread?

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Baffling error in Background worker code

    I have some memory that working with bitmaps across threads can cause trouble, but I forget the details about it. Still, Paul has a good point. You appear to be copying a detail from a larger image, and it appears to be a rectangular detail. There is likely a better way to accomplish the ultimate goal.
    My usual boring signature: Nothing

  6. #6

    Thread Starter
    New Member
    Join Date
    Dec 2021
    Posts
    6

    Re: Baffling error in Background worker code

    There is only the one Background worker. Yes the picture box gets accessed when the form loads, bitmaps are declared and their contents are loaded from the resources file. The destination bitmap is displayed and once a choice is made, the source bitmap is set to the choice. All that is done before the Background Worker starts. Here is the code:
    Code:
    Imports System.ComponentModel
    
    Public Class Form1
        Private X, Y, W, H, HowWide, HowTall As Integer
        Private Source, Destination, AN, RU, ADO, DOJ As Bitmap
    
        Private Sub BtnReset_Click(sender As Object, e As EventArgs) Handles BtnReset.Click
            Destination = My.Resources.Images.DOJ
            PictureBox1.Image = Destination
        End Sub
    
        Private Sub BtnStart_Click(sender As Object, e As EventArgs) Handles BtnStart.Click
            Destination = DOJ
            If RBRudy.Checked Then Source = RU
            If RBAnn.Checked Then Source = AN
            If RBADO.Checked Then Source = ADO
            BGWProcess.RunWorkerAsync()
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            DOJ = My.Resources.Images.Don
            Destination = DOJ
            AN = My.Resources.Images.Ann
            RU = My.Resources.Images.Rudy
            ADO = My.Resources.Images.Adolf
            PictureBox1.Image = Destination
            HowWide = PictureBox1.Width - 1
            HowTall = PictureBox1.Height - 1
        End Sub
    
        Private Sub BGWProcess_DoWork(sender As Object, e As DoWorkEventArgs) Handles BGWProcess.DoWork
            For Y = 0 To HowTall 'process one row at a time for the effect
                For X = 0 To HowWide
                    Destination.SetPixel(X, Y, Source.GetPixel(X, Y)) ' Generates System.InvalidOperationException: 'Object is currently in use elsewhere.""
                Next
                BGWProcess.ReportProgress(Y)
            Next
        End Sub
    
        Private Sub BGWProcess_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BGWProcess.ProgressChanged
            TxtProgress.Text = e.ProgressPercentage.ToString
            PictureBox1.Image = Destination
        End Sub
    
    End Class

  7. #7
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: Baffling error in Background worker code

    Your problem is almost definitely because you're trying to edit a My.Resources image

  8. #8
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: Baffling error in Background worker code

    Quote Originally Posted by .paul. View Post
    Your problem is almost definitely because you're trying to edit a My.Resources image
    No that's not it. All accessing an image resource does is create a Bitmap object on the fly. You're free to use it as you would any other image.

    His problem is that the same image is being accessed by multiple threads. Create a project with an image resource and a button that executes the following code:-
    Code:
            Dim img = My.Resources.TestImage
    
            Task.Run(Sub()
                         img.SetPixel(10, 10, Color.Red)
                     End Sub)
    
    
            Task.Run(Sub()
                         img.SetPixel(10, 20, Color.Red)
                     End Sub)
    Rapidly click that button multiple times and eventually, it will bomb out with the exact error OP is experiencing.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  9. #9

    Thread Starter
    New Member
    Join Date
    Dec 2021
    Posts
    6

    Re: Baffling error in Background worker code

    Quote Originally Posted by .paul. View Post
    Your problem is almost definitely because you're trying to edit a My.Resources image
    I'm editing a copy of a copy of the my.Resources image. I can do that successfully in a timer tick.

    DOJ = My.Resources.Images.Don
    Destination = DOJ

    I'm changing the bitmap "Destination", 2levels away from the resource image.
    The bitmap "Source" is a copy of the corresponding resources file, 1 level away

    Destination.SetPixel(X, Y, Source.GetPixel(X, Y))

    Nothing tries to alter the resource images

  10. #10
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Baffling error in Background worker code

    Quote Originally Posted by Zomalaja View Post
    I'm editing a copy of a copy of the my.Resources image. I can do that successfully in a timer tick.

    DOJ = My.Resources.Images.Don
    Destination = DOJ

    I'm changing the bitmap "Destination", 2levels away from the resource image.
    It certainly doesn't look that way. Images are reference type objects so there's no copies of Images being made there. A resource is data compiled into your assembly. When you get a property of My.Resources, that data is extracted and an object created. Your first line of code does that and assigns that object to the DOJ variable. The next line doesn't copy anything. It just assigns that same object to the Destination variable. If you access those two variables on different threads at the same time, you're accessing the same object on different threads.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  11. #11
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: Baffling error in Background worker code

    To make a real copy...

    Code:
    Destination = DirectCast(DOJ.Clone, Bitmap)

  12. #12
    Member
    Join Date
    Nov 2005
    Posts
    36

    Re: Baffling error in Background worker code

    PictureBox is a UI element, and I guess the bitmap accessed here is part of it?
    If so, I would not touch the bitmap from anything but the UI thread.

  13. #13

    Thread Starter
    New Member
    Join Date
    Dec 2021
    Posts
    6

    Re: Baffling error in Background worker code

    I don't know what "part of it" means, sorry
    the destination bitmap gets its pixels changed in the Background worker - It's supposed to, but it fails
    The PictureBox Image is set to the destination bitmap in the report progress code where i thought a UI object could be changed

  14. #14
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: Baffling error in Background worker code

    The bitmap is assigned to a PictureBox so of course the UI thread is going to access it in order to render it. While it's doing this, the BGW is also trying to write to it on another thread.

    If you alter the test code I posted earlier:-
    Code:
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Dim img = My.Resources.TestImage
    
            Task.Run(Sub()
                         img.SetPixel(10, 10, Color.Red)
                     End Sub)
    
    
            Task.Run(Sub()
                         Dim k = img.GetPixel(10, 20)
                     End Sub)
    
    
        End Sub
    The change here is that now one thread is reading and one is writing and it still bombs out with "Object is currently in use".
    Last edited by Niya; Sep 2nd, 2024 at 01:20 PM.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  15. #15
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Baffling error in Background worker code

    So, you need a different copy of the bitmap, not just a different copy of a reference to the bitmap, which is what you have now. Still, it seems likely that there is a better way to do this. Copying one pixel at a time seems inefficient. Those are some notoriously slow methods with some means to speed them up. If the reason for using the background thread was because the process was too slow, then there is probably a better solution that can be done in the foreground. After all, you seem to just obtaining rectangular subsets of a single image. What will change about that? It looks like you will always get a certain region if one radiobutton is checked, a different region for a second radiobutton, and so on. It feels like this is a problem that can be solved by throwing memory at it, such as keeping the subsets as separate bitmaps ahead of time and just selecting one on check changed.
    My usual boring signature: Nothing

  16. #16
    Member
    Join Date
    Nov 2005
    Posts
    36

    Re: Baffling error in Background worker code

    > The PictureBox Image is set to the destination bitmap

    Which I believe makes the image a UI element.
    UI elements can only be changed on the UI thread.
    A BGW thread can be any thread (but also randomly) the UI thread, so it may randomly work.

    If fex you tried changing the text of a textbox from a BGW you would get a more direct error message from.NET, but this uses GDI, so anything better than OutOfMemory is a win.

    Fix? Do the changes to the image on the UI thread, or do the changes in a BGW on copies of the images, and then copy the images to Picturebox.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width