Question Multi Threading with seperate classes

DevLex

Member
Joined
May 7, 2011
Messages
5
Programming Experience
5-10
Hello,

I'm trying to dive into what I consider a deeper end of VB.net to see how far I can go with it.

I have a project created, ironically called "My First Server".
The aim of this is to create a server which can handle multi clients but additionally isn't the commonly shown tutorial setup of a console application.

So it is created as a Windows Form application.

The main form (Public Class PrimaryForm) consists of only one control which is a listbox control. This is named LogOutput.

The code within the PrimaryForm (at present) is:

Public Class PrimaryForm
    Private Sub PrimaryForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        LogOutput.Items.Add("Welcome to the 'Server'. The current date and time is " & Date.Now)
        Dim Server As New ServerClass
        Server.Start()
    End Sub

    Public Sub Msg(ByVal mesg As String)
        If Me.LogOutput.InvokeRequired Then
            Dim d As New MsgCallBack(AddressOf Msg)
            Me.Invoke(d, New Object() {mesg})
        Else
            mesg.Trim()
            Me.LogOutput.Items.Add(Date.Now & mesg)
            Debug.WriteLine(Date.Now & mesg)
        End If
    End Sub

    Delegate Sub MsgCallBack(ByVal mesg As String)
End Class


As you can see, I have a second class which is called upon called ServerClass.
This is in a seperate file entirely and looks like this.

Imports System.Net.Sockets
Imports System.Net
Imports System.Threading

Public Class ServerClass
    Private ServerThread As New Thread(New ThreadStart(AddressOf StartServer))

    Public Sub Start()
        ServerThread.Start()
    End Sub

    Private Sub StartServer()
        Dim listener As New TcpListener(IPAddress.Any, 8888)
        Dim client As TcpClient
        Dim counter As Integer = 0

        PrimaryForm.Msg(" >> Started Server")
        listener.Start()
        client = listener.AcceptTcpClient
        PrimaryForm.Msg(" >> Client Connected")
    End Sub
End Class


Upon running the code... The LogOutput is my eyes to show me whats happening at the time (as you'd expect I guess by the name).

The first line of the Load for PrimaryForm works and displays a welcome message.
I also know that the ServerClass is called and the thread started because it's call back to PrimaryForm's MSG function shows the debug message in Visual Studio.

However, it's not updating the ListBox with the entries from ServerClass for example this:
PrimaryForm.Msg(" >> Started Server")


I've done a bit of reading about and I understand there's considered an unsafe and safe method of threads talking to controls created by other threads and believe I've covered that and proven it's working if all held in the same class but when it's two seperate classes it doesn't work.

If anyone can debug the reason and/or provide me advice I'd be greatly appreciative.

Summary of the programmed function above is at first to open a listener and write updates to a listbox log.

Kind regards,

DevLex
 
I guess sometimes it helps to think about something if you've explained it to others... After reading through my own post I realised one thing... There shouldn't actually be a debug message, it is just that the invoke required property returns false all the time.
 
Default form instances are thread specific, meaning referring to default form from a secondary thread will just return you a new instance of that form. Since that instance is created in that thread InvokeRequired will be False and you will not see anything in your existing UI thread form instance. You can pass the reference to the form instance to the server class so that the server class can pass back messages to it.
 
Hi JohnH,

Thanks for the reply.

I'm a little lost however, I thought that because I was calling "New Thread" that this required a safe invoke as it's calling the UI Thread from an 'Other' Thread.

In which cases would the invoke apply then - When I call from another Form, not class?

Best Regards,

DevLex
 
InvokeRequired applies when accessing a control from a different thread than it was created in.

If you don't want to create a dependency in server class class for the PrimaryForm type you can define an event which any consumer of the class can handle.
 
Hi JohnH,

Thank you again for replying.
Would you be able to recommend any resources/webpages you may have come across that might aid me in understanding the inner workings of this more?

I'm interested, but I think perhaps I've bitten off quite a chunk of information that I've just not quite digested.


Additionally I'm not 100% sure how I created a dependency on PrimaryForm - I'm guessing because I'm creating a 'New instance' in PrimaryForm? (Dim Server as New ServerClass in PrimaryForm.vb).

When I run my application, the first thing that happens is the form launches and from this the rest of the program initiates. Am I to guess you'd start the thread somewhere (and somehow) in My.Application as opposed to Form1?

Thanks again!

Best regards,

DevLex.
 
I'm not 100% sure how I created a dependency on PrimaryForm
In Server class you are referring to PrimaryForm, that's a dependency. What if you wanted to use the same Server class from a different form? Referring to PrimaryForm would be pretty useless then. If you look at any class in framework you see they have events that you can handle to get notified about things. You can use any class and and number of instances and handle the event for any of them without any dependency.
As for learning resources I guess any beginner book that teaches about classes and events and such will do.
 
Back
Top