Home All Groups Group Topic Archive Search About
Author
1 Dec 2006 5:13 PM
Jay
Given the following code I am wondering if SyncLock is required.  Because I
am using system.timer is there already this type of lock behaviour in place?
I need to assure that I'm only selecting one distinct record at a time per
thread...

Public Class Form1

   Private MessageArray() As MessageHandler
   Private MH As MessageHandler

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

       MH = New MessageHandler

       Dim i As Integer
       Dim iTo As Integer = 4  '4 threads
       Dim iFrom As Integer = 1

       ReDim MessageArray(iTo - iFrom)
       Dim Msg As MessageHandler
       For i = iFrom To iTo
           Msg = New MessageHandler()
           MessageArray(i - iFrom) = Msg
           'pass parameters to the new thread
           Msg.i = i
           Msg.MainForm = Me
           Dim ts As ThreadStart
           ts = New ThreadStart(AddressOf Msg.ProcessingOutboundThread)
           Dim wrkThread As Thread
           wrkThread = New Thread(ts)
           Msg.CurrentThread = wrkThread
           wrkThread.SetApartmentState(ApartmentState.STA)
           wrkThread.Name = i.ToString() 'for easier tracing
           wrkThread.Start()
       Next
       'end start
   End Sub

End Class

Class MessageHandler

   Public MainForm As Form1
   Public i As Integer
   Public CurrentThread As Thread
   Public iThreadId As Integer
   Public cnString As String =
"server=servername;database=dbname;uid=username;pwd=password"
   Private WithEvents Timer1 As System.Timers.Timer

   Private Sub Timer1_Elapsed(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed

       iThreadId = Thread.CurrentThread.GetHashCode()

       Dim cn As SqlConnection
       cn = New SqlConnection(cnString)
       Dim cmd As SqlCommand
       Dim dtr As SqlDataReader

       Try
          Try
               cmd = New SqlCommand("select top 1 * from queue_table where
time_to_send=1", cn)
               cn.Open()
                   dtr = cmd.ExecuteReader()
                   If dtr.HasRows() = True Then
                       dtr.Read()
                       Dim varE As String = dtr("employeetosendto")
                       Dim varM As String = dtr("employeemessageaddress")
                       dtr.Close()
                       cmd = New SqlCommand("update queue_table set
time_to_send=0 where employee='" & varE & "'", cn)
                       cmd.ExecuteNonQuery()
Call_Send_Message_Sub_Here 'call another sub pass employeemessageadress as
param
                       cmd = New SqlCommand("update queue_table set
sentmessage=1 where employee='" & varE & "'", cn)
                       cmd.ExecuteNonQuery()
    end if
               Catch ex As Exception
                   msgbox(ex.Message.ToString())
               Finally
                   If cn.State = ConnectionState.Open Then cn.Close()
               End Try
           End If
       Catch ex As Exception
              msgbox(ex.Message.ToString())
       Finally
           If cn.State = ConnectionState.Open Then cn.Close()
       End Try
   End Sub

   Public Sub ProcessingOutboundThread()
       Dim iThreadId As Integer
       iThreadId = Thread.CurrentThread.GetHashCode()

       Timer1 = New System.Timers.Timer
       Timer1.Interval = 5000 ' 5 seconds
       Timer1.Start()

       Application.Run()
   End Sub
End Class

I'd appreciate any feedback on how I can make this a more threadsafe app or
more stable app.  Thanks a lot.

Jay

Author
1 Dec 2006 7:18 PM
Brian Gideon
Jay wrote:
Show quoteHide quote
> Given the following code I am wondering if SyncLock is required.  Because I
> am using system.timer is there already this type of lock behaviour in place?
> I need to assure that I'm only selecting one distinct record at a time per
> thread...
>
> Public Class Form1
>
>    Private MessageArray() As MessageHandler
>    Private MH As MessageHandler
>
>    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles MyBase.Load
>
>        MH = New MessageHandler
>
>        Dim i As Integer
>        Dim iTo As Integer = 4  '4 threads
>        Dim iFrom As Integer = 1
>
>        ReDim MessageArray(iTo - iFrom)
>        Dim Msg As MessageHandler
>        For i = iFrom To iTo
>            Msg = New MessageHandler()
>            MessageArray(i - iFrom) = Msg
>            'pass parameters to the new thread
>            Msg.i = i
>            Msg.MainForm = Me
>            Dim ts As ThreadStart
>            ts = New ThreadStart(AddressOf Msg.ProcessingOutboundThread)
>            Dim wrkThread As Thread
>            wrkThread = New Thread(ts)
>            Msg.CurrentThread = wrkThread
>            wrkThread.SetApartmentState(ApartmentState.STA)
>            wrkThread.Name = i.ToString() 'for easier tracing
>            wrkThread.Start()
>        Next
>        'end start
>    End Sub
>
> End Class
>
> Class MessageHandler
>
>    Public MainForm As Form1
>    Public i As Integer
>    Public CurrentThread As Thread
>    Public iThreadId As Integer
>    Public cnString As String =
> "server=servername;database=dbname;uid=username;pwd=password"
>    Private WithEvents Timer1 As System.Timers.Timer
>
>    Private Sub Timer1_Elapsed(ByVal sender As Object, ByVal e As
> System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed
>
>        iThreadId = Thread.CurrentThread.GetHashCode()
>
>        Dim cn As SqlConnection
>        cn = New SqlConnection(cnString)
>        Dim cmd As SqlCommand
>        Dim dtr As SqlDataReader
>
>        Try
>           Try
>                cmd = New SqlCommand("select top 1 * from queue_table where
> time_to_send=1", cn)
>                cn.Open()
>                    dtr = cmd.ExecuteReader()
>                    If dtr.HasRows() = True Then
>                        dtr.Read()
>                        Dim varE As String = dtr("employeetosendto")
>                        Dim varM As String = dtr("employeemessageaddress")
>                        dtr.Close()
>                        cmd = New SqlCommand("update queue_table set
> time_to_send=0 where employee='" & varE & "'", cn)
>                        cmd.ExecuteNonQuery()
> Call_Send_Message_Sub_Here 'call another sub pass employeemessageadress as
> param
>                        cmd = New SqlCommand("update queue_table set
> sentmessage=1 where employee='" & varE & "'", cn)
>                        cmd.ExecuteNonQuery()
>     end if
>                Catch ex As Exception
>                    msgbox(ex.Message.ToString())
>                Finally
>                    If cn.State = ConnectionState.Open Then cn.Close()
>                End Try
>            End If
>        Catch ex As Exception
>               msgbox(ex.Message.ToString())
>        Finally
>            If cn.State = ConnectionState.Open Then cn.Close()
>        End Try
>    End Sub
>
>    Public Sub ProcessingOutboundThread()
>        Dim iThreadId As Integer
>        iThreadId = Thread.CurrentThread.GetHashCode()
>
>        Timer1 = New System.Timers.Timer
>        Timer1.Interval = 5000 ' 5 seconds
>        Timer1.Start()
>
>        Application.Run()
>    End Sub
> End Class
>
> I'd appreciate any feedback on how I can make this a more threadsafe app or
> more stable app.  Thanks a lot.
>
> Jay

Jay,

The Elapsed event on System.Timers.Timer will run on a thread from the
ThreadPool if SynchronizingObject is null.  When SynchronizingObject is
set to a Form or Control then the Timer will automatically marshal the
Elapsed event onto the thread hosting that Form or Control.  In your
case the Elapsed event is running on another thread because you aren't
setting the SynchronizingObject property.

The thread running ProcessingOutboundThread isn't doing much.  In fact,
the only thing it's doing is getting a Timer started.  After that it
just blocks on Application.Run consuming system resources.  You can
just as easily get the Timer started on the main UI thread inside the
Form_Load event.

Better yet, set the SynchronizingObject property to Form1 and the
Elapsed event will always run on the main UI thread.  That will
absolutely guarentee that the queries will be executed one at a time.
And of course, since there wouldn't be more than one thread in play the
issue of thread-safety is moot.

Brian