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

时间:2019-06-30 10:14:46

标签: vb.net multithreading

我有一个用VB.net编写的旧版winform应用程序,该应用程序有多个线程(3-4个线程),每个线程在应用程序处于活动状态时循环运行。 每个线程周期都会遍历项目列表并检查其状态。 例如,一个线程具有与DB相关的项目列表,它检查它们是否更改并采取相应措施。 另一个线程具有需要从另一个TCP服务器更新的项目列表。 每个线程完成其列表后,便具有Sleep(300)。
我有一个奇怪的现象,其中一个线程有时会启动,然后我看到其他线程多次运行其循环,只有第一个线程才能继续。这导致该线程的循环需要很长时间。

每个线程的循环看起来像这样:

  Do While locParent.ServiceState = IThreadMain.eServiceState.Run 

       ReadItems() ' go through the list
       Threading.Thread.Sleep(300) ' sleep

       Application.DoEvents()
 Loop

在ReadItems()代码中,还有短暂的睡眠调用(最长1000毫秒)。

我不明白为什么有时一个特定的线程睡眠/暂停很长一段时间,而另一个线程循环执行多次。

1 个答案:

答案 0 :(得分:1)

平台(OS)完全管理线程使CPU运行的时间。您无法预测任意线程何时醒来。当任意线程获取CPU时,它由.NET框架和操作系统线程调度程序决定。线程是允许并行运行任务的机制,但是线程本身在获得CPU时间时并不能提供任何保证。

如果您需要某种顺序的线程运行顺序,则可以通过某种线程同步机制(例如class ManualResetEventclass AutoResetEvent)来实现,但是在您的情况下,这可能是实际上是一种反模式。创建线程是为了允许您的代码以并行方式运行,并且如果没有充分的理由要同步线程(例如生产者使用者模式),则不应该这样做。

BTW-在大多数情况下,让线程在没有诸如Thread.Sleep(100)之类的人造睡眠的情况下循环运行而无需任何等待,反模式会损害系统的整体性能。仅当线程有有意义的工作要做时,才应运行线程。例如,如果线程处理来自TCP套接字的某些数据,则它应无限期休眠,直到来自套接字的某些数据到达为止。这样的代码应该以这种方式示意性地编写。

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.

此算法有一些替代方法,例如,如果某些处理要等到一段时间才能完成,并且向Event.WaitOne()添加一些超时,并且在这种情况下需要进行一些处理(发送错误消息),但是通常线程不应仅仅为了防止线程旋转而“随机等待” 100ms或500ms。它们应该等待直到其他线程将其唤醒,因为它们有一些数据需要处理或有意义的超时到期。

如果唤醒线程只是为了进行检查,就没有什么要处理的,这种情况可以通过其他方式(例如,如果我们知道何时来自TCP套接字的数据到达)来确定,那么这种“随机等待”就是浪费CPU周期数。

在某些情况下,这种“随机等待”是不可避免的(例如,如果第三方API不能表示异步事件到达),但是在大多数情况下,此类代码是代码设计不当的标志。