none
thread safe event handlers and a Dot Net vent RRS feed

  • Question

  • Hi Folks,

    I would first like to thank all those who read and consider this and especially to those who can offer aid.

    I am a 25 year casual programmer who was quite happy, as were my employers, with my tools being VB6 calling C DLLs OR Delphi 6/7. As these tools no longer run in Win 8/10 I am trying to get a grip on Dot Net programming and am finding it quite frustrating as I am spending excessive amounts of time and effort in satisfying Dot Net rather than spending it satisfying my app.

    At the moment I am trying to make sense of multi threading. I have written a wrapper class around the TcpListener class to add some functionality and to save me writing the same boilerplate every time I need a listener. My wrapper is in it's own assembly which is referenced by the app which supplies the handler. I am happy with my wrapper in a one connection only version. I am trying to extend it so that it will support multiple concurrent connections by launching a new thread for each new connection request. On a new connection the Listener instantiates a new client, raises an event and passes the client to the handler in EventArgs. My problem arises in the event handler. At run time VS2015 raises an Invalid Operation Exception.
    "Additional information: Cross-thread operation not valid: Control 'TextBoxRcv' accessed from a thread other than the thread it was created on". I am OK with that. I get the error. My problem is in finding a resolution.

    The Intellisense 'Click here for help' link returned 217.88 cm of information(13 pages @ 16.76 cm per on my screen) of which 100.56 cm was the 'here's  how to avoid it' example. One full metre of Dot Net code just to feed Dot Net itself so my app can display some text from a 2 line method. And, after all that, it is entirely unclear on how it prevents the problem.

    https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(EHInvalidOperation.WinForms.IllegalCrossThreadCall)
    ;k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-VB)&rd=true

    The example on making safe calls glaringly omits the nugget that solves the problem; the 'Dim d As New SetTextCallback(AddressOf SetText)' reference is not mentioned. What the H E Double Toothpicks is a 'SetTextCallback()'? I get that it is related to the SetText() method but that is not enough. A few words on this and I probably would have been on my way 4 days ago.

    Intellisense offered to solve it with 4 different options of creating methods, classes, and modules. I tried them all. None will compile.

    I have been in many of the MS documention articles, MS forums, Code Project forums and Google for 4 days and can find no clear, sane description of the solution. What I have found (not just in threading, but in other spheres) is that Dot Net has, for no apparent reason, multiple ways of doing the same thing. None of which are cross compatible, nor fully and clearly documented.

    And so I ask 2 things. Firstly, can someone please provide me with a clearly explained methodology for safely passing Event Arguments from thread to thread and having them interact, and, secondly, if anyone from MS is reading this, please have a very, very deep conversation on Dot Net and it's documentation, for to me it is nothing but Win 98 DLL hell writ very, Very, VEry, VERy, STUPIDLY, LARGE.

    BTW: here is my handler.
    Public Sub Srv_OnClientConnect(sender As Object, e As ClientConnectEventArgs) Handles Srv.ClientConnect
            Dim c As TcpClient = e.ConnectedClient
            TextBoxRcv.Text = c.ReceiveText()
        End Sub 
    Thanks again

        
    Saturday, August 26, 2017 10:43 AM

Answers

  • Hi Frank,

    I am completely missing something. In my wrapper class I explicitly declare a handler

    Public Class JDITCPServer : Implements IDisposable
        Public Event ClientConnect As EventHandler

    ...

    End Class

    and in the calling app I implement that handler

     Public Sub Srv_OnClientConnect(sender As Object, e As ClientConnectEventArgs) Handles Srv.ClientConnect
            Dim c As JDITCPClient = e.Connection
            Dim s As String = Nothing
            Threading.Thread.Sleep(2000)
            c.ReceiveText(s)
            tbRcv.Text = s
        End Sub

    I have a handler, so what is AddHandler adding? And where? And why?

    Thanks


    This can get heady but I'll spare that. ;-)

    Cor wasn't wrong; if VB knows to create a delegate, it will. Using a delegate isn't optional and never was, but in VB you just don't always recognize that you're using one. With threading though, it doesn't know to create one.

    Do some digging around about what a delegate it (it's really a signature as much as anything else) and "why do I have use one anyway?", but you can't talk to it directly:

    I realize that's about a proxy but the concept is similar here.

    A few days ago there was a question asked about a splash screen and in that Karen correctly answered it but I think it went over the OP's head. Still though, because threading is involved, you have to give it a way to communicate one to another.

    If you'll have a look:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/6972dccb-1a27-4f7e-b64c-677c4a42c747/cant-modify-or-close-splashscreen-threading-error-vstudio-2017?forum=vbgeneral

    Scroll down about half-way (it's long!) and you'll see where I showed Form1 "talking to" the form that's on the other thread. That's about controls and you're not dealing with controls here, but the idea is the same.

    ***** EDIT *****

    This looks to be a pretty good article:

    https://www.codeproject.com/Articles/13607/A-Beginner-s-Guide-to-Delegates

    I'm only just now reading it also, but I like his approach on it.


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    Saturday, August 26, 2017 12:44 PM

All replies

  • I have an example that shows how to update a windows control using a Task with the option to cancel. 

    See my MSDN Code sample. WindowsApplication1, Form1 is were things are triggered while in DatabaseOperations_vb, class Worker is the operations that update a control back in the forms project. Note there is a line AwaitTask.Delay(500), this should be removed, was placed there to slow things down for the demo.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Saturday, August 26, 2017 11:42 AM
    Moderator
  • Uncle Bob,

    You've read a lot. 

    However, C# developers are more busy on Internet than VB developers and sometimes convert their programs to VB. 

    The first VB is developed by the old VB6 team. They tried to realize something (and succeeded in my perception) better van VB6 (maybe the step was to huge but nobody who have ever programmed in VB7 and newer would never want to go back to VB6). 

    What is written about event handlers and thread safety is mostly about a transition in thinking from C# to VB. 

    VB implements automatic the delegates for the Handlers, something which is not done with C#.

    Think about that when you read about it.

    Also try to avoid to use multi threading to much. It could be done with every NT computer on a single core (thread) processor. It are simply 2 different things.  In some situations is using multi threading making your program slower. 


    Success
    Cor


    Saturday, August 26, 2017 11:46 AM
  • This teaches me nothing. It only throws more nonsensical code at me. Which is my original problem with the documentation.

    Saturday, August 26, 2017 12:04 PM
  • Bob,

    You need to do this through a delegate:

    https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/delegates/

    In that MSDN document, read the section entitled "Delegates and Events".


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, August 26, 2017 12:09 PM
  • Hi Frank,

    I am completely missing something. In my wrapper class I explicitly declare a handler

    Public Class JDITCPServer : Implements IDisposable
        Public Event ClientConnect As EventHandler

    ...

    End Class

    and in the calling app I implement that handler

     Public Sub Srv_OnClientConnect(sender As Object, e As ClientConnectEventArgs) Handles Srv.ClientConnect
            Dim c As JDITCPClient = e.Connection
            Dim s As String = Nothing
            Threading.Thread.Sleep(2000)
            c.ReceiveText(s)
            tbRcv.Text = s
        End Sub

    I have a handler, so what is AddHandler adding? And where? And why?

    Thanks


    Saturday, August 26, 2017 12:25 PM
  • This teaches me nothing. It only throws more nonsensical code at me. Which is my original problem with the documentation.

    If that is what you think, so be it. In the future I will steer clear of providing assistance to you as my current reply has apparently offended you.

    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Saturday, August 26, 2017 12:29 PM
    Moderator
  • Hi Karen,

    It hasn't offended me. It has just added to my frustration for it does not explain or describe what is happening. It is just more code that does not help me UNDERSTAND what is missing/wrong with my event and handler. I did not expect you to to code my exact solution, I am more than willing to do that, and if I have beat my forehead against my desk until my brain is exposed to achieve it, that is fine. But I cannot begin doing it until I understand what and why I am aiming for. Posting code using a different method than I have does not achieve that for me. 

    I apologize for any offense taken at my response for it was not intended as I believe that my post made it clear that knowledge and understanding was paramount.

    Have a pleasant day



    Saturday, August 26, 2017 12:41 PM
  • Hi Frank,

    I am completely missing something. In my wrapper class I explicitly declare a handler

    Public Class JDITCPServer : Implements IDisposable
        Public Event ClientConnect As EventHandler

    ...

    End Class

    and in the calling app I implement that handler

     Public Sub Srv_OnClientConnect(sender As Object, e As ClientConnectEventArgs) Handles Srv.ClientConnect
            Dim c As JDITCPClient = e.Connection
            Dim s As String = Nothing
            Threading.Thread.Sleep(2000)
            c.ReceiveText(s)
            tbRcv.Text = s
        End Sub

    I have a handler, so what is AddHandler adding? And where? And why?

    Thanks


    This can get heady but I'll spare that. ;-)

    Cor wasn't wrong; if VB knows to create a delegate, it will. Using a delegate isn't optional and never was, but in VB you just don't always recognize that you're using one. With threading though, it doesn't know to create one.

    Do some digging around about what a delegate it (it's really a signature as much as anything else) and "why do I have use one anyway?", but you can't talk to it directly:

    I realize that's about a proxy but the concept is similar here.

    A few days ago there was a question asked about a splash screen and in that Karen correctly answered it but I think it went over the OP's head. Still though, because threading is involved, you have to give it a way to communicate one to another.

    If you'll have a look:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/6972dccb-1a27-4f7e-b64c-677c4a42c747/cant-modify-or-close-splashscreen-threading-error-vstudio-2017?forum=vbgeneral

    Scroll down about half-way (it's long!) and you'll see where I showed Form1 "talking to" the form that's on the other thread. That's about controls and you're not dealing with controls here, but the idea is the same.

    ***** EDIT *****

    This looks to be a pretty good article:

    https://www.codeproject.com/Articles/13607/A-Beginner-s-Guide-to-Delegates

    I'm only just now reading it also, but I like his approach on it.


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    Saturday, August 26, 2017 12:44 PM
  • Thanks Frank,

    I get the proxy analogy, the delegate keeps the 2 threads separate from each other. But just to help solidify the concept in my head, I must ask...given that the delegate must exist in some thread space somewhere, be it the caller's, the called's, or it's own, wouldn't the same cross thread problem exist? And if the delegate doesn't have a problem across threads then why does the original? I realize I have opened a circular line of thought, but there is clearly a break that I can't see. Could you enlighten me on why the delegate works? 

    Saturday, August 26, 2017 1:12 PM
  • Thanks Frank,

    I get the proxy analogy, the delegate keeps the 2 threads separate from each other. But just to help solidify the concept in my head, I must ask...given that the delegate must exist in some thread space somewhere, be it the caller's, the called's, or it's own, wouldn't the same cross thread problem exist? And if the delegate doesn't have a problem across threads then why does the original? I realize I have opened a circular line of thought, but there is clearly a break that I can't see. Could you enlighten me on why the delegate works? 

    That's a good question and one that I don't have an answer for (regarding threading at least), but do recognize that when you define a delegate with a given signature, the compiler is actually creating a class (it's actually a structure, not a class, but it's similar) and it derives from System.Delegate.

    Where that instance exists -- I don't know!


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, August 26, 2017 1:22 PM
  • I will accept that it is one of the great unknowns. Despite that , the concept makes sense to me now. Thank you sir.
    Saturday, August 26, 2017 1:40 PM
  • I will accept that it is one of the great unknowns. Despite that , the concept makes sense to me now. Thank you sir.

    Threading can get to be a headache (wait until you get to parallelization for real fun) but when you need it, it's there.

    You're welcome. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, August 26, 2017 1:42 PM