Click here to Skip to main content
15,899,023 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I'm trying to understand threading, but I can't find a simple answer as to how it works.

I've been looking at examples, but I am having trouble adapting those examples to what I need, everything relates to objects that are already on the main form. But, mine are not, they are created on event. I don't understand why it is saying anything about forms, as I am experimenting to try and get this to work in any way, so I just have everything sitting on the main form rather than separating it into classes.

Is anyone able to explain what happens when using threading in lamens terms...

I've got a background working thread, I've got a delegate declared, (I think) it needs to hold the data to be passed to the main thread (Form thread)

Within sub TCP, I have a variable = show which is linked to the updateform() delegate. updateform() holds datastring which is passed by the sender.

at the end of the sub tcp - show = addressof txtboxcreate which then runs through all that code.

Where am I supposed to put the code to have the object tb, loaded onto form1.flowlayoutpanel? Is there supposed to be something more in the delegate creation?

<pre>Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Threading.Thread
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Threading

Public Class main
    Private tcpthread As System.Threading.Thread
    Public Shared datastring As String
    Public Shared counttotal As Integer
    Private Sub main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim tcpthread As New System.Threading.Thread(AddressOf tcp)
        tcpthread.IsBackground = True
        tcpthread.Start()
    End Sub
    Private Delegate Sub updateform(ByVal datastring)
    Private Sub updatefrmtb(ByVal tb As TextBox)
        Me.FlowLayoutPanel1.Controls.Add(tb)
    End Sub
    Private Sub tcp()
        Dim show As updateform
        Dim lf As Decimal = 23
        Dim server As TcpListener
        Dim datastring As String = Nothing
        server = Nothing
        Try
            ' Set the TcpListener on port 13000. 
            'Dim port As Int32 = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Iain-KVS", "p1", Nothing)
            '  Dim ipstring As String = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Iain-KVS", "IP", Nothing)
            Dim port As Int32 = 13000
            Dim localaddr As IPAddress = IPAddress.Parse("127.0.0.1")
            server = New TcpListener(localaddr, port)

            ' Start listening for client requests.
            server.Start()
            '       server.AcceptSocket()

            ' Buffer for reading data 
            Dim bytes(1024) As Byte
            Dim data As String = Nothing

            ' Enter the listening loop. 
            'While True
            '         MsgBox("Waiting for a connection... ")

            ' Perform a blocking call to accept requests. 
            ' You could also user server.AcceptSocket() here.


            Dim client As TcpClient = server.AcceptTcpClient()


            ' Get a stream object for reading and writing 
            Dim stream As NetworkStream = client.GetStream()

            Dim i As Int32
            ' Loop to receive all the data sent by the client.
            i = stream.Read(bytes, 0, bytes.Length)
            'While (i &lt;&gt; 0)
            ' Translate data bytes to a ASCII string.
            data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
            'MsgBox(data)

            ' Process the data sent by the client.
            'data = data.ToUpper()
            Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(data)


            ' Send back a response.
            stream.Write(msg, 0, msg.Length)
            '         MsgBox("Sent: {0}", data)

            '              i = stream.Read(bytes, 0, bytes.Length)
            datastring = (data)


            ' End While

            ' Shutdown and end connection
            client.Close()
            'End While
        Catch e As SocketException
            Console.WriteLine("SocketException: {0}", e)
        Finally
            server.Stop()
        End Try
        show = AddressOf txtboxcreate

    End Sub 'Main
    Private Sub txtboxcreate(ByVal sender As System.Object)
        Dim count As Integer = 1
        Dim tb As New TextBox
        Name = ("TxtBox" &amp; CStr(counttotal))
        Dim text As String = datastring
        With tb
            .Name = Name
            .Text = Text
            .Multiline = True
            .Height = 150
            .Width = 250
            .ReadOnly = True
            .ScrollBars = False
            .MaxLength = 100
            .Tag = 20
            .BackColor = Color.Black
            .ForeColor = Color.White
            '           move unused properties under here'
            '           tb.ScrollBars = ScrollBars.Both
            '           tb.MaxLength = 100
            '           tb.Height = 100
            '           tb.AutoSize = True
            ' add events to the textbox created


            '       AddHandler tb.MouseClick, AddressOf Me.TextBox1_MouseClick
            '   Form1.textboxestime.Add(tb, 0)
        End With
        count = (count + counttotal)
        ' this defines where the textboxes appear
        updatefrmtb(tb)
    End Sub
End Class</pre><pre></pre>
Posted

Your difficulties are quite natural. The problems involving exchange between threads are not as trivial as they may seem. They include the problems of accessibility couples with problems of synchronization. Some aspects, event the thread start, are not adequately explained in MSDN documentation.

To read/write data from/to you thread, I suggested using a thread wrapper. Many thins about threading and the concept of data exchange between threads are explained in my past answers:
How to pass ref parameter to the thread[^],
Change parameters of thread (producer) after it is started[^],
MultiThreading in C#[^].

This is some VB.NET sample: Passing arguments to a threaded LongRunningProcess[^].

Another aspect is sending some updates from a thread to UI.

You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

—SA
 
Share this answer
 
Comments
Mendaharin 20-Mar-14 2:25am    
Thanks SA - looks like I've got a lot of reading ahead of me...
Sergey Alexandrovich Kryukov 20-Mar-14 10:42am    
You do. You are welcome. Are you going to accept the answer formally (green "Accept" button)?
In all cases, your follow-up questions will be welcome.
—SA
I kinda of understand what is going on here now. But I know I'm going to run into some funny threading stuff later on.

You need to call what you want to add. That's what the Invoke thing does.

All I needed to do was

VB
Private Sub updatefrm(ByVal sender As TextBox)
        'The tcp sub runs as a seperate thread. If you try to call the form directly it won't work as you are cross threading
        'you need to invoke "Call" the control you want to do the work with - in this case flowlayoutpanel1
        If InvokeRequired Then
            Invoke(Sub() FlowLayoutPanel1.Controls.Add(sender))
        Else
            FlowLayoutPanel1.Controls.Add(sender)
        End If
    End Sub


By doing this, I'm checking to see if the flowlayoutpanel is part of the background thread. If it's not, I then call (invoke) that control to the current worker thread. Now I can add stuff to it :)

Originally I just had flowlayoutpanel1.control.add(sender) But as I hadn't called the panel to put it on, it comes up with cross threading issues.

3 simple lines of code. Drives me nuts sometimes.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 20-Mar-14 10:47am    
Not exactly. FlowLayoutPanel cannot be "a part of a thread" or not. Let's say it was created and added to your running UI in some thread created by OS in the very beginning. I call it UI thread. And you call the code you show above in some thread, too. InvokeRequired merely checks up if they are the same threads or not. If they are the same, Invoke is not required.

Therefore, you only need to do this check if this code is called in different threads, sometimes UI thread, sometimes not. As in most designs you know it in advance, InvokeRequired call is not needed.

Please read about invocation in my answer. I can explain how it works internally:
http://www.codeproject.com/Tips/149540/Simple-Blocking-Queue-for-Thread-Communication-and.

Please, don't post non-answers as "solutions". You have to move it to the question using "Improve question". Also, I did not get any notification.

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900