views:

188

answers:

4

I'm simulating some threading in a Windows Service, and the Thread.Start routine for each of my threads points directly to the following:

Private WithEvents CheckForOrdersTimer As System.Threading.Timer

Private Sub timerCheckForContracts_Tick(ByVal stateInfo As Object)
    ' Ticks every 5 seconds, then spawns threads until we're at our max
    Do

        If ThreadCollection.Count < MaxThreads Then

            Dim t As New Threading.Thread(AddressOf SomeThreadingCode()
            ThreadCollection.Add(t)
            t.Start()

        End If
    Loop

End Sub


Private Sub SomeThreadingCode()
    Do
        Thread.Sleep(1000)
        If Me.ThreadsShouldContinue = False Then  ' Global thread-stopper
            Exit Sub
        End If
        If (New Random).NextDouble > 0.8 Then  ' On average, wait 5 seconds
            Exit Do
        End If

    Loop

    ' Remove this thread from the main collection
    ThreadCollection.Remove(Thread.CurrentThread)

End Sub

Pretty simple - the threads aren't even doing anything yet, but with more than two threads running at the same time, my processor (Core 2 Duo 2.4 w/ 4GB) gets pegged and Windows gets really sluggish. According to what I've read, Thread.Sleep shouldn't be consuming any resources at all while it waits, but it may as well be running in a tight timing loop.

Can anybody explain to me what's going on here?

EDIT: Per the requests, I've expanded the amount of code I'm using. I was initially doing some database work before spawning each thread, but I've removed it and the processor maximization still occurs with just the code here (and, of course, the OnStart method for the Windows Service.

A: 

There is not enough here to help really. How are the threads being created? What is happening on the main thread? Console or WinForm app? If you are creating and destroying threads every one-five seconds, that is going to take resources. Research Threadpool for ways to cache threads so you can avoid the costs of creating and destroying them.

JDMX
+2  A: 

Well, there are 4 statements in your code, 3 of them are wrong. ThreadsShouldContinue cannot work well because VB.NET doesn't have the "volatile" keyword. The Random statement cannot work well because you create a new instance of the Random class every time, preventing it from being truly random. And the Remove() method call cannot work well because you don't use the SyncLock statement.

The Sleep() call is the only statement without an issue. Does that explain the problem? Probably not. Use Debug + Break All to see what the threads are doing.

Hans Passant
I'm okay with a slightly longer wind-down time, so it seems that VOLATILE (or VB.NET equivilent code) isn't required, only suggested to ensure that changes to the variable are picked up immediately. I've moved the "Random" to a single instance that I call through a function, using Sync-locking, so I think I'm okay there now. Third, since the thread only ever removes itself from the List(of Thread), is SyncLock still necessary? I'll add it anyways, I suppose.
rwmnau
Volatile semantics are required, the JIT optimizer can store the variable in a register otherwise. It loops forever. Use a ManualResetEvent instead. Multiple threads mutating a list is *not* safe, the list can get corrupted. SyncLock is very much required.
Hans Passant
Thanks for the clarification - I'll wrap my list management in some SyncLock. I suppose the idea of adding a removing from the list at the same time, from different threads, should cause some concern.
rwmnau
A: 

This code should not be looping, the sleeps look ok. And sleep uses no CPU. YOu other threads are spinning somewhere.

Plus you should use an Event to signal termination rather than looping on a sleep/bool test

Silently ignoring all exceptions is not going to make things easier to debug either

pm100
I originally thought the only way to stop my threads during the Service OnStop was to Abort them all - I was going to handle the cleanup in the Catch block. If there's a way to use an event to handle the notification to stop, I'd much prefer that - can you point me towards an example of that? The code I've seen online uses an "If Not Closing Then" check, similar to what I'm doing here.
rwmnau
+3  A: 

timerCheckForContracts_Tick is running an infinite loop, and never goes to sleep, etc. Even if you are "ticking" it every 5 seconds, there is no code within the loop to prevent it from consuming CPU cycles, forever checking:

    If ThreadCollection.Count < MaxThreads Then
Justin Ethier
Damn, beat me to it :-) That's the answer!
Dan Puzey
Wow - I can't believe I missed that. I intended to add some Exit logic to prevent this, but clearly I forgot. I've switched the loop up for a "Do Until Count >= MaxThreads" and it drops my processor utilization to almost nothing. Thanks - +15 to you.
rwmnau