Search code examples
vb.netmultithreadingtimerprogram-entry-point

How to make sub main behave like form?


VB.NET.

Trying to make a Sub Main behave like a form. In the sense that it doesn't consume the processor and Sub Main keeps running indefinitely, with a Timer Event that will fire approx once per second.

The code below gives me the behavior I want but I don't fully understand how the EventWaitHandle works. My question is... Does anyone know if this is a good approach or if there might be an easier way to just have a Sub Main that basically doesn't do anything but allow a Timer event to fire?

Imports System.Threading
Module MainMod
    Public Sub Main(args As String())

        Dim waitHandle = New System.Threading.EventWaitHandle(True, EventResetMode.AutoReset, "", False)

        Dim timer = New Timer(AddressOf OnTimerElapsed, Nothing, TimeSpan.Zero, TimeSpan.FromSeconds(1))

        Do While True
            waitHandle.WaitOne(TimeSpan.FromSeconds(20)) 
        Loop

    End Sub

    Private Sub OnTimerElapsed(state As Object)
        Debug.WriteLine(DateAndTime.Now.ToString)
    End Sub

End Module

Solution

  • EventWaitHandle in your code is really not doing anything special. It is simply allowing you to wait infinitely. However, this is not the standard use for EventWaitHandle. EventWaitHandle is used generally to synchronize between different threads. It allows one thread to wait for another thread to signal that something happened.

    It doesn't seem to me that you need this functionality, you simply need to wait.

    You can simply call Console.ReadLine. This will cause the main thread to wait, but will cause the application to exit if the user inputs a line.

    Another way is to use Thread.Sleep which will cause the main thread to wait also. Putting that in a loop will cause the main thread to wait indefinitely.

    Consider the following code:

    Public Sub Main(args As String())
        Dim timer = New Timer(AddressOf OnTimerElapsed, Nothing, TimeSpan.Zero, TimeSpan.FromSeconds(1))
        Do While True
            Thread.Sleep(TimeSpan.FromSeconds(20))
        Loop
    End Sub
    
    Private Sub OnTimerElapsed(state As Object)
        Debug.WriteLine(DateAndTime.Now.ToString)
    End Sub
    

    Another comment about your code is that using the System.Threading.Timer class will cause the OnTimerElapsed to be called a second time while the first call is not finished if the first call is taking more that one second (the timer period value) to complete.

    This means that the Timer does not wait for the previous invocation to complete before issuing a new one.

    If this is the behavior that you want, then it is fine.

    If not, then you can replace your application with a simple loop and use Thread.Sleep like this:

    Public Sub Main(args As String())
        Do While True
            Thread.Sleep(TimeSpan.FromSeconds(1))
            OnTimerElapsed()
        Loop
    End Sub
    
    Private Sub OnTimerElapsed()
        Debug.WriteLine(DateAndTime.Now.ToString)
    End Sub