Quantcast
Channel: VBForums - Visual Basic .NET
Viewing all articles
Browse latest Browse all 27248

[RESOLVED] Execution of For loop skips to end of SyncLock

$
0
0
Hi Folks

Im trying to make a timed scheduler in a threaded vb windows form application. With one job on the schedule everything works fine. But with two jobs on the schedule the main For loop inside the SyncLock() in the timer elapsed event never executes.
When I step through the elapsed event sub execution gets to the For loop and then jumps to the end of the SyncLock() with out executing the For or anything after it within the locked block.
I cant understand why this happens, maybe someone with fresh eyes could see whats going on?

the relevant code is below.

In Scheduler.vb the problems start at line 84
VB Code:
  1. Imports System.Threading
  2. Imports System.Timers
  3.  
  4. ' Example creation of this singleton class:
  5. ' Dim MyScheduler As Scheduler = Scheduler.GetScheduler
  6.  
  7. Public NotInheritable Class Scheduler
  8.     Inherits System.Timers.Timer
  9.  
  10.     Private Class Job
  11.         ' Class for adding items to the schedule
  12.         Public Sub New(period As TimeSpan, contextKey As UInteger)
  13.             If period > TimeSpan.Zero Then
  14.                 JobKey = contextKey
  15.                 Start = Now
  16.                 Finish = Start + period
  17.             Else
  18.                 Throw New ArgumentOutOfRangeException
  19.             End If
  20.         End Sub
  21.         Public Period As TimeSpan
  22.         Public Start As DateTime
  23.         Public Finish As DateTime
  24.         Public JobKey As UInteger
  25.         Public ThreadId As Integer
  26.     End Class
  27.  
  28.     ' Dictionary to hold the scheduled jobs
  29.     Private Shared _schedule As New Dictionary(Of UInteger, Job)
  30.     ' List to hold references to the working threads
  31.     Private Shared _threads As New List(Of Threading.Thread)
  32.     ' The reference to the single scheduler instance
  33.     Private Shared _singleInstance As Scheduler
  34.     ' SyncLock objects
  35.     Private Shared _scheduleLock As New Object
  36.     Private Shared _threadsLock As New Object
  37.     Private Shared _instanceLock As New Object
  38.  
  39.     Private Sub New()
  40.         ' Setup and start the timer with an interval of 3 seconds
  41.         MyBase.New()
  42.         AddHandler MyBase.Elapsed, AddressOf Scheduler_Elapsed
  43.         MyBase.Interval = 3000
  44.         MyBase.Enabled = True
  45.         MyBase.Start()
  46.     End Sub
  47.  
  48.     Public Sub AddJob(period As TimeSpan, contextKey As UInteger)
  49.         SyncLock (_scheduleLock)
  50.             Dim count As UInteger = _schedule.Count
  51.             If Not count = 0 Then
  52.                 ' Adjust for zero-base
  53.                 count -= 1
  54.                 ' Create copy of keys
  55.                 Dim keys(count) As UInteger
  56.                 _schedule.Keys.CopyTo(keys, 0)
  57.                 ' Step through jobKeys on schedule
  58.                 For index As Integer = count To 0
  59.                     If _schedule.Item(keys(index)).JobKey = contextKey Then
  60.                         ' Remove any obsolete jobs
  61.                         _schedule.Remove(keys(index))
  62.                     End If
  63.                 Next
  64.             End If
  65.             ' Add new job
  66.             _schedule.Add(_schedule.Count, New Job(period, contextKey))
  67.         End SyncLock
  68.     End Sub
  69.  
  70.     Private Sub Scheduler_Elapsed(source As Object, e As ElapsedEventArgs) Handles MyBase.Elapsed
  71.         Dim check As DateTime = Now
  72.         Dim count As UInteger = _schedule.Count
  73.  
  74.         If count > 0 Then
  75.             SyncLock (_scheduleLock)
  76.                 ' Adjust for zero-base
  77.                 count -= 1
  78.                 Dim keys(count) As UInteger
  79.                 ' Copy all the keys from the shcdule to an array
  80.                 ' as the keys may not be in order and For...Each
  81.                 ' cannot be used when removing items
  82.                 _schedule.Keys.CopyTo(keys, 0)
  83.                 ' Step through each of the keys in the keys array
  84.                 For index As Integer = count To 0                       '<----- EXECUTION SKIPS FROM HERE TO END SYNCLOCK
  85.                     ' Check if any of the jobs on the schedule are due
  86.                     If DateTime.Compare(check, _schedule.Item(keys(index)).Finish) > 0 Then
  87.                         ' Create and start a new thread
  88.                         Dim jobThread As New Thread(AddressOf DoJob)
  89.                         ' Save the thread ID to the job object - this allows the job to know which thread is handling it
  90.                         _schedule.Item(keys(index)).ThreadId = jobThread.ManagedThreadId
  91.                         ' Add the new thread to the list of threads - to keep track of all the threads
  92.                         SyncLock (_threadsLock)
  93.                             _threads.Add(jobThread)
  94.                         End SyncLock
  95.                         ' Start the work thread, passing the job object - so that it knows which DUT context to use
  96.                         jobThread.Start(_schedule.Item(keys(index)))
  97.                         ' Remove the job from the schedule - to prevent the job from being started on subsequent elapsed events
  98.                         _schedule.Remove(keys(index))
  99.                     End If
  100.                 Next
  101.             End SyncLock
  102.         End If
  103.     End Sub
  104.  
  105.     Private Sub DoJob(ByVal job As Object)
  106.         ' Use the JobKey to get the context object for the relevant DUT
  107.         Dim dutContext As New DeviceUnderTest
  108.         dutContext = Form1.currentDuts.Item(job.JobKey)
  109.  
  110.         ' Get and run the next step in the program
  111.         ' NextProgramStep() just shows a message box at the moment
  112.         dutContext.NextProgramStep()
  113.  
  114.         ' After work, remove thread from list of threads
  115.         SyncLock (_threadsLock)
  116.             Dim count As UInteger = _threads.Count
  117.             If count > 0 Then
  118.                 ' Step through job threadIds of current threads
  119.                 For index As UInteger = count - 1 To 0
  120.                     ' Check if any threads have the same id as the current job
  121.                     If _threads(index).ManagedThreadId = job.ThreadId Then
  122.                         ' Remove any thread working on this job
  123.                         _threads.Remove(_threads.Item(index))
  124.                     End If
  125.                 Next
  126.             End If
  127.         End SyncLock
  128.     End Sub
  129.  
  130.     Public Shared ReadOnly Property GetScheduler As Scheduler
  131.         ' Ensures only one instance of the scheduler is created
  132.         Get
  133.             If _singleInstance Is Nothing Then
  134.                 SyncLock (_instanceLock)
  135.                     If _singleInstance Is Nothing Then
  136.                         _singleInstance = New Scheduler
  137.                     End If
  138.                 End SyncLock
  139.             End If
  140.             Return _singleInstance
  141.         End Get
  142.     End Property
  143.  
  144.     Overloads ReadOnly Property Interval As Double
  145.         ' Reads the timer interval property (set in Scheduler.New())
  146.         Get
  147.             Return MyBase.Interval
  148.         End Get
  149.     End Property
  150. End Class

In Form1.vb
VB Code:
  1. Imports System.Text
  2. Imports System.Linq
  3. Imports System.Net
  4. Imports System.Net.Sockets
  5. Imports System.Timers
  6.  
  7. Public Class Form1
  8.  
  9.     Dim sched As Scheduler
  10.     Public Shared currentDuts As New Dictionary(Of UInteger, DeviceUnderTest)
  11.     Dim newDutKey As UInteger
  12.  
  13.     Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
  14.         sched = Scheduler.GetScheduler
  15.         Dim testDUT1 As New DeviceUnderTest()
  16.         Dim testDUT2 As New DeviceUnderTest()
  17.         Dim newKey As UInteger = currentDuts.Count
  18.  
  19.         ' Add the 2 new DUT jobs to the schedule
  20.         ' (DUT class is empty class at the moment)
  21.         currentDuts.Add(newKey, testDUT1)
  22.         currentDuts.Add(newKey + 1, testDUT2)
  23.         sched.AddJob(TimeSpan.FromSeconds(4.0), newKey)
  24.         sched.AddJob(TimeSpan.FromSeconds(30.0), newKey + 1)
  25.     End Sub
  26. End Class

Viewing all articles
Browse latest Browse all 27248

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>