Threading Question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Bill Schanks

    Threading Question

    I have a form that gets opened, and it a separate thread I want a
    timer at the bottom of the form to update while the datagridview is
    updating.

    In my main form I have this:
    Dim t As New Thread(AddressO f ChildForm.Updat eRetrieveTimer)
    t.Start()
    <<Snip>>

    Here is the code for the thread:
    Public Sub UpdateRetrieveT imer()
    Dim ts As TimeSpan
    Dim s As String
    Do While Not g_bRetreiveDone (g_ChildFormNum ber)
    ts = Date.Now - g_dtStartQuery
    s = String.Format(" {0:d2}:{1:d2}:{ 2:d2}", ts.Hours,
    ts.Minutes, ts.Seconds)
    Me.rssRetrieveT ime.Text = s
    Loop
    End Sub

    The problem is on the line 'Me.rssRetrieve Time.Text = s'. It pauses
    here.
  • Tom Shelton

    #2
    Re: Threading Question

    On 2008-09-30, Bill Schanks <wschanks@gmail .comwrote:
    I have a form that gets opened, and it a separate thread I want a
    timer at the bottom of the form to update while the datagridview is
    updating.
    >
    In my main form I have this:
    Dim t As New Thread(AddressO f ChildForm.Updat eRetrieveTimer)
    t.Start()
    ><<Snip>>
    >
    Here is the code for the thread:
    Public Sub UpdateRetrieveT imer()
    Dim ts As TimeSpan
    Dim s As String
    Do While Not g_bRetreiveDone (g_ChildFormNum ber)
    ts = Date.Now - g_dtStartQuery
    s = String.Format(" {0:d2}:{1:d2}:{ 2:d2}", ts.Hours,
    ts.Minutes, ts.Seconds)
    Me.rssRetrieveT ime.Text = s
    Loop
    End Sub
    >
    The problem is on the line 'Me.rssRetrieve Time.Text = s'. It pauses
    here.
    You can not access any form controls on a background thread - period. If you
    want the update to occur, then you must use Me.Invoke to marshal the call back
    to the forms thread.

    A better alternative, if you are using VB2005 and up is to use the
    BackgroundWorke r component to handle this. Just make sure, that you do your
    interface updates in ProgressChanged event.

    --
    Tom Shelton

    Comment

    • Bill Schanks

      #3
      Re: Threading Question

      I have been trying to get the backgroundworke r to work. Here is what I
      have. The problem is the .dowork section runs for 5 seconds or so but
      the datagridview doesn't have any results on it.

      Private WithEvents ReportWorker As
      System.Componen tModel.Backgrou ndWorker

      <<snip>>
      'Get the results (Background worker)
      _dtStartQuery = Date.Now
      ReportWorker = New System.Componen tModel.Backgrou ndWorker
      ReportWorker.Wo rkerReportsProg ress = True
      ReportWorker.Ru nWorkerAsync()
      _ChildForm.tsBt nStop.Enabled = True

      'Show timer while data is retrieved
      While ReportWorker.Is Busy
      _ts = Date.Now - _dtStartQuery
      _ChildForm.rssR etrieveTime.Tex t =
      String.Format(" {0:d2}:{1:d2}:{ 2:d2}.{3:d3}", _
      _ts.Hours, _ts.Minutes, _ts.Seconds,
      _ts.Millisecond s)
      Application.DoE vents()
      End While
      <<snip>>

      Private Sub ReportWorker_Do Work(ByVal sender As Object, _
      ByVal e As System.Componen tModel.DoWorkEv entArgs) _
      Handles ReportWorker.Do Work


      _ChildForm.Spoc _ev_resultsTabl eAdapter.Fill(_ ChildForm.RCT_E V_QADataSet.spo c_ev_results,
      _
      _dtAsOf, _
      _sRptID, _
      _sDB, _
      _sBL, _
      _sCID, _
      _sMgr, _
      _bCommentsMissi ng)

      End Sub

      Tom Shelton wrote:
      On 2008-09-30, Bill Schanks <wschanks@gmail .comwrote:
      I have a form that gets opened, and it a separate thread I want a
      timer at the bottom of the form to update while the datagridview is
      updating.

      In my main form I have this:
      Dim t As New Thread(AddressO f ChildForm.Updat eRetrieveTimer)
      t.Start()
      <<Snip>>

      Here is the code for the thread:
      Public Sub UpdateRetrieveT imer()
      Dim ts As TimeSpan
      Dim s As String
      Do While Not g_bRetreiveDone (g_ChildFormNum ber)
      ts = Date.Now - g_dtStartQuery
      s = String.Format(" {0:d2}:{1:d2}:{ 2:d2}", ts.Hours,
      ts.Minutes, ts.Seconds)
      Me.rssRetrieveT ime.Text = s
      Loop
      End Sub

      The problem is on the line 'Me.rssRetrieve Time.Text = s'. It pauses
      here.
      >
      You can not access any form controls on a background thread - period. If you
      want the update to occur, then you must use Me.Invoke to marshal the call back
      to the forms thread.
      >
      A better alternative, if you are using VB2005 and up is to use the
      BackgroundWorke r component to handle this. Just make sure, that you do your
      interface updates in ProgressChanged event.
      >
      --
      Tom Shelton

      Comment

      • Branco Medeiros

        #4
        Re: Threading Question

        Hi, Bill.

        It seems you're doing the same thing again (i. e., updating a control
        in a background thead), only now it's the Datagrid.

        I suspect that when you call
        _ChildForm.Spoc _ev_resultsTabl eAdapter.Fill(. ..) from inside the
        DoWork method, the update gets blocked, 'cause anything running inside
        the DoWork method is in a secondary thread.

        As Tom suggested, one way to do what you want could be to use the
        ProgressChanged event of the BackgroundWorke r (which kicks in on the
        main thread) to update the display. In this case, the filling of the
        grid should be left in the main thread (as you were originally doing
        it seems).

        Another approach, as Tom also pointed out, is to use the form's invoke
        method. It turns out a control (and the form) has the method
        InvokeRequired which returns true if the current thread can't update
        the user interface. If so, then you must resort to calling the form's
        Invoke method, passing the address of the method to execute and an
        array with the method's parameters. Invoke will then ensure that the
        method is executed in a thread that can update the UI (usually the
        main thread).

        As a side note, considering your first example, it seems also you are
        acessing, from your secondary thread, a variable which gets data
        updated from the main thread (g_bRetreiveDon e(g_ChildFormNu mber)).
        Ideally, all access to variables shared between threads should be
        "interlocke d". In your case, maybe you don't get into trouble, cause
        it seems it's only the main thread that updates the variable, but keep
        this in mind for future reference.

        Finally, notice that you have a **very tight** loop running inside
        UpdateRetrievet imer. I mean, the thing is running *non-stop* probably
        hundreds or even thousands of times per second without much need,
        since its only job is to update the screen once per second. It would
        be nice if you put it to rest at regular intervals, say 500 ms...

        Using your original approach as reference, here's a possible (but not
        tested, mind you) solution:

        <example>
        'In the child form
        Delegate Sub Updater(Text As String)


        Private mFinishUpdate As Boolean
        'used to lock shared access to the variable above
        Private mLock As New Object

        Private Property Finished As Boolean
        Get
        Dim Result As Boolean
        SyncLock(mLock)
        Result = mFinished
        End SyncLock
        Return Result
        End Get
        Set(Value As Boolean)
        SyncLock(mLock)
        mFinished = Value
        End SyncLock
        End Set
        End Property

        Sub UpdateTimer(Tex t As String)
        Static DoUpdate As Updater = AddressOf UpdateTimer
        If Me.InvokeRequir ed Then
        'this runs in the secondary thread
        Me.Invoke(DoUpd ate, New Object(){Text})
        Else
        'this runs in the main thread
        Me.rssRetrieveT ime.Text = Text
        End If
        End Sub

        Public Sub UpdateRetrieveT imer()
        Dim ts As TimeSpan
        Dim s As String
        Do While Not Finished
        ts = Date.Now - g_dtStartQuery
        s = String.Format(" {0:d2}:{1:d2}:{ 2:d2}", _
        ts.Hours, ts.Minutes, ts.Seconds)
        UpdateTimer(s)
        System.Threadin g.Thread.Sleep( 500)
        Loop
        End Sub
        </example>

        Hope this helps.

        Regards,

        Branco.

        ------------------
        Bill Schanks wrote:
        I have been trying to get the backgroundworke r to work. Here is what I
        have. The problem is the .dowork section runs for 5 seconds or so but
        the datagridview doesn't have any results on it.
        >
        Private WithEvents ReportWorker As
        System.Componen tModel.Backgrou ndWorker
        >
        <<snip>>
        'Get the results (Background worker)
                    _dtStartQuery = Date.Now
                    ReportWorker = New System.Componen tModel.Backgrou ndWorker
                    ReportWorker.Wo rkerReportsProg ress = True
                    ReportWorker.Ru nWorkerAsync()
                    _ChildForm.tsBt nStop.Enabled = True
        >
                    'Show timer while data is retrieved
                    While ReportWorker.Is Busy
                        _ts = Date.Now - _dtStartQuery
                        _ChildForm.rssR etrieveTime.Tex t =
        String.Format(" {0:d2}:{1:d2}:{ 2:d2}.{3:d3}", _
                            _ts.Hours, _ts.Minutes, _ts.Seconds,
        _ts.Millisecond s)
                        Application.DoE vents()
                    End While
        <<snip>>
        >
        Private Sub ReportWorker_Do Work(ByVal sender As Object, _
                ByVal e As System.Componen tModel.DoWorkEv entArgs) _
                Handles ReportWorker.Do Work
        >
        _ChildForm.Spoc _ev_resultsTabl eAdapter.Fill(_ ChildForm.RCT_E V_QADataSet.spo ­c_ev_results,
        _
                    _dtAsOf, _
                    _sRptID, _
                    _sDB, _
                    _sBL, _
                    _sCID, _
                    _sMgr, _
                    _bCommentsMissi ng)
        >
            End Sub

        Comment

        Working...