简体   繁体   English

VB.net多线程问题-线程长时间睡眠

[英]VB.net multithread issue - thread goes to sleep for long times

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. 我有一个用VB.net编写的旧版winform应用程序,该应用程序有多个线程(3-4个线程),每个线程在应用程序处于活动状态时都循环运行。 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. 例如,一个线程具有与DB相关的项目列表,它检查它们是否更改并采取相应措施。 Another thread has a list of items that needs to be updated from another TCP-Server. 另一个线程具有需要从另一个TCP服务器更新的项目列表。 After each thread finishes it's list, it has Sleep(300). 每个线程完成其列表后,便具有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). 在ReadItems()代码中,还有短时间(最大1000 ms)的Sleep调用。

I cannot understand why sometimes one specific thread sleeps/suspends for a long while, and the other threads loops executes multiple times. 我不明白为什么有时一个特定的线程会长时间休眠/挂起,而另一个线程循环执行多次。

The time when a thread gets a CPU to run is fully managed by the platform (OS). 线程使CPU运行的时间由平台(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. 当任意线程获取CPU时,它由.NET框架和操作系统线程调度程序决定。 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. 线程是一种允许并行运行任务的机制,但是线程本身在获得CPU时间时并不能提供任何保证。

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. 如果您需要某种顺序的线程运行顺序,则可以通过某种线程同步机制(例如, class ManualResetEvent class AutoResetEventclass AutoResetEvent )来实现,但是在您的情况下,这实际上可能是一种反模式。 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. 顺便说一句-在大多数情况下,让线程在没有诸如Thread.Sleep(100)之类的人工睡眠的情况下循环运行就没有任何等待,这会损害系统的整体性能。 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. 例如,如果线程处理来自TCP套接字的某些数据,则它应无限期休眠,直到来自套接字的某些数据到达为止。 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. 此算法有一些替代方法,例如,如果某些处理要等到一段时间才能完成,并且向Event.WaitOne()添加一些超时,并且如果发生这种情况,则需要完成一些处理(发送错误消息),但是通常线程不应该这样做。 •为了防止线程旋转,“随机等待” 100ms或500ms。 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. 如果唤醒线程只是为了检查而已,那么就没有什么要处理的,这种情况可以通过其他方式(例如,如果我们知道何时来自TCP套接字的数据到达)来确定,那么这种“随机等待”就是浪费CPU周期。

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. 在某些情况下,这种“随机等待”是不可避免的(例如,如果第三方API并不表示异步事件到达),但是在大多数情况下,此类代码表明代码设计不正确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM