Reputation: 85
I have a legacy winform application written in VB.net, that has several threads (3-4 threads), each running in a loop while the application is active.
Each thread cycle goes through a list of items and checks their status.
For example, one thread has a list of items that are DB-related and it checks if they changed and acts accordingly.
Another thread has a list of items that needs to be updated from another TCP-Server.
After each thread finishes it's list, it has Sleep(300).
I have a weird phenomenon that one of the threads, sometimes starts, then I see that the other threads runs their loop multiple times, only then the first thread continues. This cause a situation that the loop of that thread takes a long time.
The loop of each thread looks something like this:
Do While locParent.ServiceState = IThreadMain.eServiceState.Run
ReadItems() ' go through the list
Threading.Thread.Sleep(300) ' sleep
Application.DoEvents()
Loop
Inside the ReadItems() code there are also Sleep calls, for short times (1000 ms max).
I cannot understand why sometimes one specific thread sleeps/suspends for a long while, and the other threads loops executes multiple times.
Upvotes: 0
Views: 377
Reputation: 1232
The time when a thread gets a CPU to run is fully managed by the platform (OS). You can't predict when an arbitrary thread wakes up. It's up the .NET framework and operating system thread scheduler when and an arbitrary thread gets the CPU. Threads are the mechanism how to allow running tasks in parallel way, but threads themselves doesn't gives you any guarantees when they get the CPU time.
If you need some sort of order in which threads should be ran you can do it by some kinds of threading synchronization mechanisms (for instance class ManualResetEvent
or class AutoResetEvent
), but in your case this could be actually an anti-pattern. Threads are created to allow your code to run in paralel way and if there isn't a good reason why you want to synchronize your threads (like producer consumer pattern), you shouldn't do it.
BTW - letting threads to run in a cycle without any waits just with some artificial sleeps like Thread.Sleep(100) is in most cases and anti-pattern that hurts the system overall performance. Threads should be ran only if they have a meaningful work to do. For instance, if a thread processes some data from the TCP socket, it should be sleeping indefinitely until some data from the socket arrives. Code like this should be written schematically in this way.
AutoResetEvent Event; // Shared variable.
ConcurrentQueue<SomeDTO> Queue; // Shared thread safe queue.
// THREAD 1.
while(true)
{
// Waits indefinitely.
Event.WaitOne();
// Read data from thread safe queue.
SomeDTO var;
if (Queue.TryDequeue(out var)==true)
{
// Process data.
}
}
// THREAD 2 - if new data arrive from TCP.
SomeDTO var=ReadDataFromTCP();
Queue.Enqueue(var);
Event.Set(); // This wakes up THREAD 1.
There are some alternatives of this algorithm, like adding some timeout to Event.WaitOne()
if some processing doesn't finish up until some time and some processing needs to be done if this happens (sending error message), but generally threads shouldn't 'randomly wait' for 100ms or 500ms just to prevent thread spinning. They should wait up until some other thread wakes them up because they have some data to process or some meaningful timeout expires.
If threads are woken up just to check up there is nothing to process - and this situation can be determined by other means (like if we know when the data from the TCP socket arrive) having such 'random waits' is just wasting of the CPU cycles.
There are some cases where such 'random waits' are unavoidable - (for instance if 3rd party API doesn't signalize asynchronous event arrival), but in most cases such code is a sign of improper code design.
Upvotes: 1