dcsimg
Results 1 to 18 of 18

Thread: Close Please

  1. #1

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    15

    Close Please

    Close Please
    Last edited by vbfailure; Jun 24th, 2019 at 04:06 AM.

  2. #2
    Fanatic Member kpmc's Avatar
    Join Date
    Sep 2017
    Posts
    1,011

    Re: Setting Control Tag from Background Worker

    No, you cant, You can however pass the Tag value into the DoWork event

  3. #3

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    15

    Re: Setting Control Tag from Background Worker

    Close Please
    Last edited by vbfailure; Jun 24th, 2019 at 04:05 AM.

  4. #4
    Fanatic Member kpmc's Avatar
    Join Date
    Sep 2017
    Posts
    1,011

    Re: Setting Control Tag from Background Worker

    Show your complete code.

  5. #5
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    102,607

    Re: Setting Control Tag from Background Worker

    Firstly, you're not doing anything "from" or "in" a BackgroundWorker. All your code is in your form. You're doing everything in your form. The BackgroundWorker simply raises events. The event handlers are methods and those methods are members of your form.

    As for your question, the answer is VERY simple. DO NOT touch a control in the DoWork event handler of a BackgroundWorker. That's it, that's all. That event handler is executed on a secondary thread and you can only safely touch controls on the UI thread. Stop trying to get around that fact.

    The BackgroundWorker has three events of interest: DoWork, ProgressChanged and RunWorkerCompleted. The whole point of the BackgroundWorker is to do work in the background. Touching controls is the very opposite of background work. The UI is, by definition, the foreground. The DoWork event is raised on a secondary thread so the handler for that event is where you do the background work and ONLY the background work. If you want to do foreground work during the process you need to do so in the ProgressChanged event handler. If you want to do foreground work after the process completes you need to do so in the RunWorkerCompleted event handler. If you need data from the UI to use in the DoWork event handler then you get it first, before you start the process.

  6. #6

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    15

    Re: Setting Control Tag from Background Worker

    Close Please
    Last edited by vbfailure; Jun 24th, 2019 at 04:05 AM.

  7. #7
    Fanatic Member kpmc's Avatar
    Join Date
    Sep 2017
    Posts
    1,011

    Re: Setting Control Tag from Background Worker

    This one is all you, JMC

  8. #8
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    102,607

    Re: Setting Control Tag from Background Worker

    There are only five members of the Control class that are safe to access on a secondary thread: InvokeRequired, Invoke, BeginInvoke, EndInvoke and CreateGraphics. Of those, you're only likely to ever use the first three. If you want to use any other member then DO NOT do so on a secondary thread. There doesn't need to be any further discussion.

  9. #9
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    102,607

    Re: Setting Control Tag from Background Worker

    Note that the fact that a member is not safe to access on a secondary thread doesn't mean that it will always fail but it might fail and you can't really be sure that it won't, even if you have tested and it hasn't previously. If you just do the right thing and don't use any Control members but those five on a secondary thread then you can never run afoul of cross-thread issues.

    It's also worth noting that cross-thread exceptions only get thrown in Debug mode. You can, if you choose, ignore them or set CheckForIllegalCrossThreadCalls to False and things will either work or fail silently in Release mode anyway. That would be very, VERY poor programming.

  10. #10

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    15

    Re: Setting Control Tag from Background Worker

    Close Please
    Last edited by vbfailure; Jun 24th, 2019 at 04:05 AM.

  11. #11
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,932

    Re: Setting Control Tag from Background Worker

    I don't quite know all the reasons behind the rules for controls and threads, so I follow the rule as JMC states it. However, in general, you can always safely read a variable from a different thread. You can never safely write to a variable from a different thread. Therefore, if it wasn't a control, then this will always be safe:

    if control.tag = 1 then

    And this will never be safe:

    control.Tag = 1

    Controls really should work that way, too, but forms can have thread affinity, which works in odd ways that I don't fully understand. That's the real danger, too. Because, both of those lines WILL work most of the time. You could even suppress cross-threading exceptions and it would do SOMETHING all of the time. The problem is that it is not guaranteed to work ALL of the time. In fact, it could work fine for years, then never work again...or any other pattern that would cause you to pull your hair out.

    For any variables accessed by multiple threads, you can always safely read, but you can never safely alter them in any way without proper precautions. Still, controls are strange animals, so don't try to circumvent appropriate actions...and better yet, don't even interact with them if you can think of any other alternative, when working with different threads.
    My usual boring signature: Nothing

  12. #12
    Fanatic Member kpmc's Avatar
    Join Date
    Sep 2017
    Posts
    1,011

    Re: Setting Control Tag from Background Worker

    Here is one for yas,

    Mission is to fill a datatable available from Class scope, which of the below options most closely matches how you would do it, and do you recon there is anything "unsafe" within any of these options, or do you feel there is zero difference.

    Code:
    #Region "Option A"
        Public Class BGW1
    
            Private DtTable As New DataTable
            Private WithEvents BGW As New ComponentModel.BackgroundWorker
    
            Private Sub RunWork()
                BGW.RunWorkerAsync()
            End Sub
    
            Private Sub BGW_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
    
                Using SqlConn As New SqlClient.SqlConnection("ConnString")
                    Using SqlDR As SqlClient.SqlDataReader = New SqlClient.SqlCommand("SELECT * FROM TABLE", SqlConn).ExecuteReader
                        DtTable.Load(SqlDR)
                    End Using
                End Using
    
            End Sub
    
        End Class
    
    #End Region
    
    
    #Region "Option B"
        Public Class BGW2
            Private DtTable As New DataTable
            Private WithEvents BGW As New ComponentModel.BackgroundWorker
    
            Private Sub RunWork()
                BGW.RunWorkerAsync(DtTable)
            End Sub
    
            Private Sub BGW_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
    
                Dim _DtTable As DataTable = DirectCast(e.Argument, DataTable)
    
                Using SqlConn As New SqlClient.SqlConnection("ConnString")
                    Using SqlDR As SqlClient.SqlDataReader = New SqlClient.SqlCommand("SELECT * FROM TABLE", SqlConn).ExecuteReader
                        _DtTable.Load(SqlDR)
                    End Using
                End Using
    
            End Sub
    
        End Class
    #End Region
    
    
    #Region "Option C"
        Public Class BGW3
            Private DtTable As DataTable '<===================================Note not initialized (New)
            Private WithEvents BGW As New ComponentModel.BackgroundWorker
    
            Private Sub RunWork()
                BGW.RunWorkerAsync()
            End Sub
    
            Private Sub BGW_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles BGW.DoWork
    
                Dim _DtTable As New DataTable
    
                Using SqlConn As New SqlClient.SqlConnection("ConnString")
                    Using SqlDR As SqlClient.SqlDataReader = New SqlClient.SqlCommand("SELECT * FROM TABLE", SqlConn).ExecuteReader
                        _DtTable.Load(SqlDR)
                    End Using
                End Using
    
                e.Result = _DtTable
    
            End Sub
    
            Private Sub BGW_RunWorkerCompleted(sender As Object, e As ComponentModel.RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
    
                DtTable = DirectCast(e.Result, DataTable)
    
            End Sub
    
        End Class
    #End Region

  13. #13
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,932

    Re: Setting Control Tag from Background Worker

    It all depends on what else is happening with that datatable while it is filling. If the answer is "nothing", and you can prove that to be the case, then they are all the same. The key problem with threading is if two different threads can access the object at the same time. If only one thread is accessing it, then there isn't a problem. It's just normally pretty hard to know that's true unless you enforce the exclusive use of the object.
    My usual boring signature: Nothing

  14. #14
    Fanatic Member kpmc's Avatar
    Join Date
    Sep 2017
    Posts
    1,011

    Re: Setting Control Tag from Background Worker

    As is, you would go with Option A for simplicity?

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

    Re: Setting Control Tag from Background Worker

    I have done so in at least one project.
    My usual boring signature: Nothing

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,286

    Re: Setting Control Tag from Background Worker

    Quote Originally Posted by vbfailure View Post
    ...

    I'm using the latest free version of VS, does it detect cross-thread exceptions 100% of the time in debug mode?

    Thanks!
    You can get an object unavailable exception anytime two threads try to access an object at the same time. It doesn't have to be GUI controls, but GUI controls would typically be the most common object that someone would try to access.

    To access a common object between threads safely, you have to guard the access to the object and .Net provides a few ways to do that. So, originally, the cross thread exception that you currently see when accessing controls from a secondary thread didn't exist. You only got an exception when two threads happen to try to access the control at the same time. Since most users were not experience enough to know how to protect their controls from simultaneous access, their programs would "blowup" at random times, raising the Object not Available exception from whichever thread got there second.

    Since using controls is such an integral piece of .Net, and educating the many users on properly guarding access to the GUI controls from secondary threads was quite problematic, the fix was to add code to the controls to check for cross thread access and to raise the cross thread exception on first detection of that situation making secondary thread access "illegal", rather than to wait until you had a real collision at some random future time. That is also why they added the CheckForIllegalCrossThreadCalls = False option so that users who know how to properly protect their objects, and don't want that extra overhead of the checking for crossthread access all the time, to disable the check.

    But, as you've found, not all properties of all controls may be trapped by the check for cross thread access.
    If you accessed a button's text from a background worker's DoWork thread you would immediately get the cross thread exception, saying that isn't allowed. If you modify the .Tag property though, you won't get that exception.

    Does that mean that the tag can be updated from any thread, without risk? I don't know. I wouldn't think so. Although its access doesn't raise the cross thread call exception, it doesn't necessarily mean that if you use it you won't get an object unavailable exception on a thread later at some random time. It would be a roll of the dice at that point. The more often you access an object from more than one thread, the greater the chance of a collision.

  17. #17
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,932

    Re: Setting Control Tag from Background Worker

    That's a good explanation of it. You make it sound like any reference type might be locked by the thread that uses it, but not locked in such a way that other threads have to wait for access. Instead, it sounds like it is locked in such a way that any other thread that attempts to access it simply fails.

    In theory, reading from the object should always be possible and safe-ish. Since context switches can happen at any time, reading from any source would give you the value at that particular point in time, though it might change before you have even looked at the value. For example,

    If someClass.SomeInteger = 1 Then

    may be true on that line, but false...perhaps even before the line has finished executing. The code would read the value from the property, but if a context switch occurred after that and before the comparison, then the property may no longer be one at the time the = 1 part is evaluated. It just was true at the time the property was read, so the If would be true and would be executed, even though the property was not one by the time the first line was run. Still safe, though, because that read of the property happened atomically and whatever path was subsequently taken was based on the value at the instant the property was read.
    My usual boring signature: Nothing

  18. #18

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    15

    Re: Setting Control Tag from Background Worker

    Close Please
    Last edited by vbfailure; Jun 24th, 2019 at 04:06 AM.

Posting Permissions

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



Featured


Click Here to Expand Forum to Full Width