Results 1 to 8 of 8

Thread: How to get a variable/value out of a thread?

  1. #1

    Thread Starter
    Lively Member
    Join Date
    May 2010
    Posts
    93

    How to get a variable/value out of a thread?

    I want to write some code to do some processing. This seems best done in a thread. But I also want some UI and general controlling passed to and from it. eg: Adding lines to a text box for general UI updating while it's running.

    Now, let's assume I might have multiple threads running, so each thread can call my UpdateUI subroutine. But the problem is, at the moment my code is using a public variable UI_Msg to pass values back from each thread to the UpdateUI subroutine. This hits me as dangerous as different threads may overwrite UI_Msg at the same time.

    Instead I tryied to attach a class to each thread, so each thread has its own UI_Msg property/value. When I then get to UpdateUI, I want to pluck this value out of that thread, so there's no risk of different threads overwriting each others msgs to UpdateUI.


    I've attached my code example.

    So all I want to do is in UpdateUI, be able to look at UI_msg from the class for the thread calling UpdateUI. eg: Obtain thread.UI_msg for example...

    Code:
    Imports System.Threading
    
    Public Class MainForm
        Public UI_msg As String
    
        ' Used to track which thread called the UI Update function.
        Private callingThread As Integer
    
        ' The Delegate that is invoked by the control on the form that needs to be updated.
        Delegate Sub UIDelegate()
    
        Private Sub UpdateUI()
            ' If InvokeRequired is true then the call is being made on a thread other
            ' than the UI thread.
            If Label1.InvokeRequired Then
                ' Call UpdateUI by invoking a delegate with the UI control
                callingThread = System.Threading.Thread.CurrentThread.ManagedThreadId()
    
                Dim newDelegate As New UIDelegate(AddressOf UpdateUI)
                Label1.Invoke(newDelegate)
            Else
                Label1.AppendText(Text + "Thread " + callingThread.ToString() + ":" + UI_msg + vbCrLf)
                ' ** How can I get the UI_MSG from the thread class? **
                UI_msg = ""
                Label1.ScrollToCaret()
            End If
        End Sub
    
        Private Sub StartJob_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartJob.Click
            UI_msg = "Starting a new thread"
            UpdateUI()
    
            Dim JobThread As New Thread(AddressOf RunJob)
            JobThread.Start()
        End Sub
    
        Class JobObjClass
            Public JobCanceled As Boolean
            Public UI_Msg As String
        End Class
    
        Sub RunJob()
            Dim StateObj As New JobObjClass()
            StateObj.JobCanceled = False
    
            Dim ctr As Integer
            ctr = 0
            While (ctr < 5 And abort = False)
                System.Threading.Thread.Sleep(1000)
                ctr = ctr + 1
                UI_msg = "Count " & ctr.ToString()
                StateObj.UI_Msg = "Count " & ctr.ToString() ' ** Want to use this instead of previous line!
                UpdateUI()
            End While
    
            StateObj.JobCanceled = True
            UI_msg = "Ending thread"
            UpdateUI()
        End Sub
    
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            abort = True
        End Sub
    End Class
    I hope this makes sense... I'm only a week or so into Visual Basic.
    Last edited by NeilF; May 28th, 2010 at 10:51 AM.

  2. #2

    Thread Starter
    Lively Member
    Join Date
    May 2010
    Posts
    93

    Re: How to get a variable/value out of a thread?

    I think I've done it

    Code:
    Imports System.Threading
    
    Public Class MainForm
        Public jobs_running As Integer
        Public abort As Boolean
    
        ' Used to track which thread called the UI Update function.
        Private callingThread As Integer
    
        ' The Delegate that is invoked by the control on the form that needs to be updated.
        Delegate Sub UIDelegate(ByVal StatusMessage As String)
    
    
        Sub UpdateUI(ByVal Message As String)
            ' If InvokeRequired is true then the call is being made on a thread other
            ' than the UI thread.
            If Label1.InvokeRequired Then
                ' Call UpdateUI by invoking a delegate with the UI control
                callingThread = System.Threading.Thread.CurrentThread.ManagedThreadId()
    
                Dim newDelegate As New UIDelegate(AddressOf UpdateUI)
                Dim args() As Object = {Message}
                Label1.Invoke(newDelegate, args)
            Else
                Label1.AppendText(Text + "Thread " + callingThread.ToString() + ":" + Message + vbCrLf)
                ' ** How can I get the UI_MSG from the thread class? **
                Label1.ScrollToCaret()
                Label2.Text = jobs_running.ToString()
            End If
        End Sub
    
        Private Sub StartJob_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartJob.Click
            jobs_running = jobs_running + 1
            UpdateUI("Starting a New Thread")
    
            Dim JobThread As New Thread(AddressOf RunJob)
            JobThread.Start()
        End Sub
    
        Sub RunJob()
            Dim ctr As Integer
            ctr = 0
            While (ctr < 5 And abort = False)
                System.Threading.Thread.Sleep(1000)
                ctr = ctr + 1
                UpdateUI("Count " & ctr.ToString())
            End While
    
            jobs_running = jobs_running - 1
            UpdateUI("Ending Thread")
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            abort = True
        End Sub
    
        Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        End Sub
    End Class

  3. #3
    Fanatic Member
    Join Date
    Nov 2007
    Posts
    520

    Re: How to get a variable/value out of a thread?

    I normally use a backgroundworker for threading...

    Backgroundworkers can NOT update a control in the dowork function, but CAN in the report/completed functions.

    So it, requires a bit of ingenuity to get it to all function.

    i am glad you think you figured it out, as i didnt really look at your code. Its always nice to see people figure things out on their own, as thats how learning works

  4. #4

    Thread Starter
    Lively Member
    Join Date
    May 2010
    Posts
    93

    Re: How to get a variable/value out of a thread?

    Quote Originally Posted by TCarter View Post
    I normally use a backgroundworker for threading...

    Backgroundworkers can NOT update a control in the dowork function, but CAN in the report/completed functions.

    So it, requires a bit of ingenuity to get it to all function.

    i am glad you think you figured it out, as i didnt really look at your code. Its always nice to see people figure things out on their own, as thats how learning works
    I sort of get what it's doing, but I've patched it togethor from examples and guess work, so I don't pretend to fully understand it... Especially the Delegate stuff

    Just wish I had an answer to this problem - http://www.vbforums.com/showthread.php?t=616099#18

  5. #5
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: How to get a variable/value out of a thread?

    A delegate is a pointer to a function. Think of it as an address on an envelope. Or a telephone number... you can't talk to you friend because he's on a different thread from you (his house vs your house) ... so you dial him up using a delegate (the phone) .. the phone acts like a proxy between your thread and your friend's thread, allowing communication (via phone wired or even cell phone towers).

    What you have there should work... it looks like you've set it up correctly.

    the InvokeRequired is like you yelling "Hey Buddy!" in your house... if he's not there (since he's at home), you have to go through your delegate (the phone) ... where it then gets routed around until it gets to your friend and he gets the message.

    it's a messy example, but I think it illustrates the concepts at least.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  6. #6
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: How to get a variable/value out of a thread?

    Code:
        Dim go As Long = 0
        Dim ct As Long = 0
        Dim lock As New Object
        Dim running As Long
        Const _toRun As Integer = 20 'try different numbers
    
        Private Sub Button2_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button2.Click
            Button2.Enabled = False
            Label1.Text = DateTime.Now.ToLongTimeString 'set up
            Threading.Interlocked.Exchange(go, 0L)
            Threading.Interlocked.Exchange(ct, 0L)
            Threading.Interlocked.Exchange(running, 0)
            For x As Integer = 1 To _toRun 'start some threads
                Dim t As New Threading.Thread(AddressOf foo)
                t.Start()
                Threading.Thread.Sleep(10) 'give each one a chance to start
            Next
            Do 'wait for all to start
                Threading.Thread.Sleep(10)
            Loop While _toRun <> Threading.Interlocked.Read(running)
    
            Button3.Enabled = True
            Threading.Interlocked.Exchange(go, 1L) 'GO!
        End Sub
    
        Private Sub Button3_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button3.Click
            Threading.Interlocked.Exchange(go, 0L) 'STOP
            Button3.Enabled = False
            aTimer.Interval = 100
            aTimer.Start()
        End Sub
    
        Dim WithEvents aTimer As New Timer()
    
        Private Sub _Tick(ByVal sender As System.Object, _
                                ByVal e As System.EventArgs) Handles aTimer.Tick
            If Threading.Interlocked.Read(running) > 0 Then Exit Sub
            aTimer.Stop()
            Label1.Text = DateTime.Now.ToLongTimeString
            Button2.Enabled = True
        End Sub
    
        Private Sub foo()
            Dim myID As Long = Threading.Interlocked.Increment(ct) 'get myID
            Threading.Interlocked.Increment(running)
            'wait for all threads to be started
            Do While Threading.Interlocked.Read(go) = 0L
                Threading.Thread.Sleep(10) 'sleep if not
            Loop
            Do
                Threading.Monitor.Enter(lock) 'lock
                updUI(myID) 'update the UI passing in myID <<< Update UI
                Threading.Monitor.Exit(lock) 'unlock
                Threading.Thread.Sleep(100) 'comment this out and see the difference
            Loop While Threading.Interlocked.Read(go) = 1L
            Threading.Interlocked.Decrement(running)
        End Sub
    
        Delegate Sub Stub(ByVal aCount As Long)
        Public myDelegate As Stub
    
        Private Sub updUI(ByVal theCount As Long)
            If Label1.InvokeRequired Then 'on UI thread
                myDelegate = New Stub(AddressOf updUI) 'no
                Label1.Invoke(myDelegate, theCount) 'this will run on the UI
                Exit Sub
            End If
            Dim s As String = Space(CInt(theCount)) & CLng(theCount).ToString
            Label1.Text = s
            Label1.Refresh()
        End Sub
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  7. #7

    Thread Starter
    Lively Member
    Join Date
    May 2010
    Posts
    93

    Re: How to get a variable/value out of a thread?

    Quote Originally Posted by dbasnett View Post
    Code:
        Dim go As Long = 0
        Dim ct As Long = 0
        Dim lock As New Object
        Dim running As Long
        Const _toRun As Integer = 20 'try different numbers
    
        Private Sub Button2_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button2.Click
            Button2.Enabled = False
            Label1.Text = DateTime.Now.ToLongTimeString 'set up
            Threading.Interlocked.Exchange(go, 0L)
            Threading.Interlocked.Exchange(ct, 0L)
            Threading.Interlocked.Exchange(running, 0)
            For x As Integer = 1 To _toRun 'start some threads
                Dim t As New Threading.Thread(AddressOf foo)
                t.Start()
                Threading.Thread.Sleep(10) 'give each one a chance to start
            Next
            Do 'wait for all to start
                Threading.Thread.Sleep(10)
            Loop While _toRun <> Threading.Interlocked.Read(running)
    
            Button3.Enabled = True
            Threading.Interlocked.Exchange(go, 1L) 'GO!
        End Sub
    
        Private Sub Button3_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button3.Click
            Threading.Interlocked.Exchange(go, 0L) 'STOP
            Button3.Enabled = False
            aTimer.Interval = 100
            aTimer.Start()
        End Sub
    
        Dim WithEvents aTimer As New Timer()
    
        Private Sub _Tick(ByVal sender As System.Object, _
                                ByVal e As System.EventArgs) Handles aTimer.Tick
            If Threading.Interlocked.Read(running) > 0 Then Exit Sub
            aTimer.Stop()
            Label1.Text = DateTime.Now.ToLongTimeString
            Button2.Enabled = True
        End Sub
    
        Private Sub foo()
            Dim myID As Long = Threading.Interlocked.Increment(ct) 'get myID
            Threading.Interlocked.Increment(running)
            'wait for all threads to be started
            Do While Threading.Interlocked.Read(go) = 0L
                Threading.Thread.Sleep(10) 'sleep if not
            Loop
            Do
                Threading.Monitor.Enter(lock) 'lock
                updUI(myID) 'update the UI passing in myID <<< Update UI
                Threading.Monitor.Exit(lock) 'unlock
                Threading.Thread.Sleep(100) 'comment this out and see the difference
            Loop While Threading.Interlocked.Read(go) = 1L
            Threading.Interlocked.Decrement(running)
        End Sub
    
        Delegate Sub Stub(ByVal aCount As Long)
        Public myDelegate As Stub
    
        Private Sub updUI(ByVal theCount As Long)
            If Label1.InvokeRequired Then 'on UI thread
                myDelegate = New Stub(AddressOf updUI) 'no
                Label1.Invoke(myDelegate, theCount) 'this will run on the UI
                Exit Sub
            End If
            Dim s As String = Space(CInt(theCount)) & CLng(theCount).ToString
            Label1.Text = s
            Label1.Refresh()
        End Sub
    Are you able to explain:-
    Threading.Interlocked.Read
    Threading.Monitor.Enter
    Threading.Monitor.Exit

    With my previous example, all my threads would run in parallel. How does the above example work? It seems at the very least to lock around the UI updating?

  8. #8
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: How to get a variable/value out of a thread?

    Quote Originally Posted by NeilF View Post
    Are you able to explain:-
    Threading.Interlocked.Read
    Threading.Monitor.Enter
    Threading.Monitor.Exit

    With my previous example, all my threads would run in parallel. How does the above example work? It seems at the very least to lock around the UI updating?
    I can, can you Threading Link


    "It seems at the very least to lock around the UI updating?" Wasn't your post about having multiple threads updating the UI? That is what it does.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

Posting Permissions

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



Click Here to Expand Forum to Full Width