Signal another thread

rfazendeiro

Centurion
Joined
Mar 8, 2004
Messages
110
Hi to all,

I'm currently makin an application that needs to read a file and update a database with the data that the file contains.

I'm using vs 2003 with sql server.

My ideia is to run some store procedure in the main thread and start another thread that show a little form indicating that the database is updating.

when the process is finnished i want to signal the thread that opened the form and kill it.

how can i do that? ho can i signal a thread to "die", an thus closing the form
 
I think you want to do it the other way around. You have your UI thread and you want to start a second thread to update the database. The secondary thread would fire an event that sends status info to the UI thread. Use a callback routine to tell the UI thread when the secondary thread finishes.

It would be something like this:

Visual Basic:
'------------------------------------------------------------------------------
'the Main form
'------------------------------------------------------------------------------

Class MainForm

    'left out code generated by the Windows Form Designer

    Dim ds As DataSource

    '---------------------------------------------------------------------------
    'handler for the Load event of the MainForm -- create a new data source
    'object
    '---------------------------------------------------------------------------

    Private Sub MainForm_Load(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
        ds = New DataSource()
    End Sub

    '---------------------------------------------------------------------------
    'handler for the Click event of the btnUpdateDb button -- start the update
    'process
    '---------------------------------------------------------------------------

    Private Sub btnUpdateDb_Click(ByVal sender As Object, _
    ByVal e As System.EventArgs)
        'show the update form here
        Dim dlgUpdateStatus As New UpdateStatusDialog
        dlgUpdateStatus.ShowDialog(Me)

        'starts the database update in an asychronous process (secondary thread)
        ds.BeginUpdateDb()
    End Sub

End Class

'------------------------------------------------------------------------------
'the form used to display the database update status
'------------------------------------------------------------------------------

Class UpdateStatusDialog

    'left out code generated by the Windows Form Designer

    Delegate Sub UpdateStatusHandler(ByVal status As String)
    
    '--------------------------------------------------------------------------
    'handles the Load event of the UpdateStatusDialog -- add the event
    'handler for the StatusChanged event
    '--------------------------------------------------------------------------

    Private Sub UpdateStatusDialog_Load(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler ds.StatusChanged, AddressOf OnStatusChanged
    End Sub

    '--------------------------------------------------------------------------
    'handler for the StatusChanged event
    '--------------------------------------------------------------------------

    Private Sub OnStatusChanged(ByVal status As String)
        'update your status form here, but you have to make
        'sure to switch to the main UI thread before updating
        'the form. NEVER update anything on the UI thread
        'from a secondary thread...you'll just end up with
        'extremely difficult troubleshooting
        If Me.InvokeRequired = True Then
            'we are not on the UI thread
            Dim handler As UpdateStatusHandler = AddressOf OnStatusChanged
            Dim args() As Object = {status}
            'switches to the UI thread
            Me.BeginInvoke(handler, args)
            Return
        End If

        'if we made it this far, we are now on the UI thread
        'go ahead and make changes to the UI
        lblStatus.Text = status
    End Sub

    '--------------------------------------------------------------------------
    'handles the Closing event of the UpdateStatusDialog -- remove the event
    'handler for the StatusChanged event
    '--------------------------------------------------------------------------

    Private Sub UpdateStatusDialog_Closing(ByVal sender As Object, _
    ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        RemoveHandler ds.StatusChanged, AddressOf OnStatusChanged
    End Sub

End Class

'------------------------------------------------------------------------------
'the object that talks to the database
'------------------------------------------------------------------------------

Class DataSource

    Private UpdateDbCallbackHandler As AsyncCallback = AddressOf UpdateDbCallback

    Public Event StatusChanged(ByVal status As String)

    Private deleg As InvokeUpdateDb
    Private ar As IAsyncResult

    '--------------------------------------------------------------------------
    'start update the DB in an asynchronous process
    '--------------------------------------------------------------------------

    Public Sub BeginUpdateDb()
        deleg = New InvokeUpdateDb(AddressOf UpdateDb)
        ar = deleg.BeginInvoke(UpdateDbCallbackHandler, Nothing)
    End Sub

    '--------------------------------------------------------------------------
    'update the DB (can call this directly instead of through BeginUpdateDb to
    'update the database in a synchronous process)
    '--------------------------------------------------------------------------

    Public Sub UpdateDb()
        'update the database here. When this is finished,
        'the UpdateDbCallback routine will be called
    End Sub

    '--------------------------------------------------------------------------
    'end the update database asynchronous process
    '--------------------------------------------------------------------------

    Public Sub EndUpdateDb()
        If Not deleg Is Nothing Then
            deleg.EndInvoke(ar)
        End If
    End Sub

    '--------------------------------------------------------------------------
    'Callback routine for UpdateDb asynchronous process
    '--------------------------------------------------------------------------

    Private Sub UpdateDbCallback(ByVal ar As IAsyncResult)
       'place code that you want performed when the update
       'is finished here
       EndUpdateDb()
    End Sub

End Class

Have some patience. It took me a while to get all this figured out. If anyone sees anything I missed or is obviously wrong, let me know. I copied and pasted snippets from one of my apps, and might have missed something.

Todd
 
HI,

i don't fully understand the code but i'm trying yo implemente this example im a little app that pretends to update a database.

What is the Private deleg As InvokeUpdateDb ??
 
Sorry. I left out a line. Place this line at the top of the DataSource class:

Visual Basic:
Private Delegate Sub InvokeUpdateDb()

That defines a Delegate object that will be used to call the UpdateDb subroutine.

Sorry for the confusion. Let me know if there is anything else that is missing or not clear.

Todd
 
i only have one problem now.

in the main form you declare ds as DataSource.

then in the UpdateStatusDialog you use this variable

Visual Basic:
    Private Sub UpdateStatusDialog_Closing(ByVal sender As Object, _
    ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        RemoveHandler ds.StatusChanged, AddressOf OnStatusChanged
    End Sub

i'm getting this error

"Name 'ds' is not declared."


I think that this is easy to resolve but don't seem to do it. Can u help?

thx in advance
 
You somehow need to get the DataSource object from the MainForm object. If the UpdateStatusDialog has access to the MainForm object, you could just change the declaration to "Public ds As DataSource". You would then need to change the statements that refer to "ds" in the UpdateStatusDialog to point to the object in the MainForm object. E.g. something like:

Visual Basic:
    Private Sub UpdateStatusDialog_Closing(ByVal sender As Object, _
    ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        RemoveHandler frmMain.ds.StatusChanged, AddressOf OnStatusChanged
    End Sub

The easiest way would be to move the "Dim ds As DataSource" to a public module and change it to "Public ds As DataSource". Although, that is not exactly the best OOP method.

Better would be to make the DataSource object a property of some other public class that both the MainForm object and the UpdateStatusDialog have access to.

Hope this helps,

Todd
 
Back
Top