0

I’m tying myself up in knots here with multithread in vb. I have a working program that I subscribe to 4 events using the add handler address of and point to a function on my main form. I have 4 separate functions that all do exactly the same thing expect for each of the 4 unique addresses for each of the functions. They have an invoke required, call my delegate thingy at the top of the functions, and then all that the function does is spawn a thread of another process and hand off processing to it.

When I use the program and I handle events from one of the subscriptions everything works great. When I start handling 2 it gets a bit slower, then I do 4 and it really clogs up. When I generate each of the subscribed events they all happen at the same time so windows would get 4 requests at the same time and presumably queue them up and work through them. So this is 1 bottleneck in my application.

What I wondered if it was possible to do, was to point the subscribed events (I.e what I do an add handler address of to) at another thread and have the raised events processed asynchronously across several threads, so I’m not Queuing them up on 1 thread. I know it’s possible because I can run 2 applications and handle the events across 2 of them split and that improves the performance, same goes for if I do 4 separate applications.

I know I have all the right bits I just can’t quite piece it together in the right order.

Public Class MainUI

Public Sub start()
    AddHandler MyEvent.EventHasHappened, AddressOf OnthisUI
    AddHandler ThreadedRoutine.Callback, AddressOf HandedBAck
End Sub

Delegate Sub On_thisUI()
Public Sub OnthisUI()

    If InvokeRequired Then
        'create a pointer to this function
        Dim MyDel As New On_thisUI(AddressOf OnthisUI)
        'call this same function from this thread
        Dim Eventargs() As Object = {sender, e}
        Invoke(MyDel, Eventargs)
        Return
    End If

    Dim Handmeoff As New ThreadedRoutine
    Dim newThread As New System.Threading.Thread(AddressOf Handmeoff.handoffexecution)
    newThread.Start()

End Sub

Public Sub HandedBAck()
    ' Update UI in here

End Sub

End Class

Public Class ThreadedRoutine
Public Shared Event Callback()
Public Sub handoffexecution()
    ' Do some work in here
    RaiseEvent Callback()

End Sub
End Class

Sorry for the rough example but this pretty much highlights what i am currently doing

The myevent.eventhashappened is the subscription that i would like to be doing concurrently across several threads rather than using the mainUI thread to receive the events and punt them out to other program threads as they are received.

I thought about putting the Addhandler subscription in another class and just calling instances of that like this

Public Class Subscribe
Public Sub New()
    AddHandler myevent.eventhashappened, AddressOf HandleMyEvent
End Sub

Public Sub HandleMyEvent()

End Sub 
End Class

Then i could just declare the 4 listener classes like this

Dim MyHandler1 as new Subscribe
Dim MyHandler2 as new Subscribe
Dim MyHandler3 as new Subscribe
Dim MyHandler4 as new Subscribe

Would that work?

Just to try and clear up what I’m trying to show happening here

The myevent.eventhappened is the hook I add at the start. An external event raises this periodically (not shown in the code for clarity at present)

This then triggers a routine in the ui which spawns a thread of a New process that handles the event, does some processing (also not shown), starts the thread and when the thread is done it calls back to the ui with some parameters to update ( again not shown)

My wished behaviour is to have that initial hook be initiated and also handled on another thread that is not the UI. I always have to return to UI at some point but I wanted to clear the first bottleneck in the pipeline.

Regards

  • 1
    Do you have some code that you can post? Cheers – d219 Jul 28 '18 at 22:53
  • 1
    Hello and Welcome to Stack Overflow! Please edit your question to include a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) so that we can get a better understanding of what's going on and perhaps be able to test it ourselves. Thank you! – Visual Vincent Jul 28 '18 at 23:02
  • We don't know that you have the right bits. You do need to post your code as a [mcve] for us to work with. Right now you have an interesting discussion, but nothing concrete for us to work with. – Enigmativity Jul 29 '18 at 00:49
  • It's kind of hard to figure out exactly what you're asking here but one thing I can mention, under most circumstances there's only one message loop per Windows Forms application (which I guess is what you're using?). When you do `Invoke` what you're actually doing is sending a message to your (single) message loop for the window to handle later, so you could in theory have 100 threads all posting messages to the message loop but they'd all end up executing one by one until they finished, which isn't a good use of threading... – jrh Jul 29 '18 at 01:02
  • ... or to put it another way, when you said "I know it’s possible because I can run 2 applications and handle the events across 2 of them split" -- that's true because the two message loops are really running on two different threads (in 2 different processes) if there's two different applications. Remember that events by themselves don't cause a handler to be executed on a different thread, they're more like an abstracted function pointer or Delegate. – jrh Jul 29 '18 at 01:04
  • 1
    One thing to keep in mind is that there's no issue executing code on a secondary thread in general. Handling an event in way means that it is necessary to marshal the call to the UI thread. The requirement of executing code on the UI thread only applies to access members of controls. If you have a method that runs for 10 minutes and updates some `Labels` here and there then you only need to marshal back to the UI thread to update the `Labels`. The rest of the code will happily execute on the background thread. It sounds like maybe you're executing code on the UI thread that doesn't need it. – jmcilhinney Jul 29 '18 at 03:03
  • Your code is a bit unclear and it's hard to see how it illustrates the problem you're having, but from what I understood: If you want to raise an event on the UI thread _from_ a background thread without blocking it, you could switch to calling [**`BeginInvoke()`**](https://msdn.microsoft.com/en-us/library/a06c0dc2(v=vs.110).aspx) instead. – Visual Vincent Jul 29 '18 at 13:29
  • 1
    Sounds like this program is suffering from the 3rd most common threading issue, a *firehose bug*. A worker thread can give the UI thread a lot of work to do, displaying the results of the work. The more threads, the more results, the more the UI thread is bogged down trying to keep. This does turn ugly in a hurry, invoke more than a thousand times per second and the UI thread starts burning 100% core. It now gets completely unresponsive. This rate is far, far higher than a human eye can observe, so is just wasted effort. You have to intentionally slow down the invoke rate to fix it. – Hans Passant Jul 29 '18 at 14:33
  • 1
    A simple way to check if that is the problem is by adding Thread.Sleep(15) before the invoke call. – Hans Passant Jul 29 '18 at 14:36

0 Answers0