Skip to content

初始化不统一控制好,引发的血案

问题描述

多线程下载:简单多个任务下载无问题,大批量下载任务,出现部分任务丢失问题

问题现象

  • 问题 1:添加完任务后,update 不自动执行,需要通过直接调用 Update 才执行(没有深究其原因,就先临时这么处理了,于是就引发后面的诡异问题)
  • 问题 2:简单多个任务下载无问题,大批量下载任务,出现部分任务丢失问题

思考问题 2

既然不大量下载就没有问题,那就弄个最简单的批量下载来复现问题,接下来就发现了以下新问题 3

  • 问题 3:共享队列刚刚添加完 item,update 的时候队列总是为空

思考问题 3

  • 思考 1:多线程导致数据不一致问题,添加在一个线程,update 在另外一个线程(已添加了锁,不应该是这个问题)
  • 思考 2:哪里把数据又删除了 或者把队列重置了(仔细检查了一遍删除相关代码无问题,把所有队列赋值的地方加个断点调试一下,发现只有 1 处地方,运行发现执行了 2 次,原因:CDLWork 对象 init 两次导致)

回顾一下代码

场景代码

  • CDLWork

    csharp
    public class CDLWork : Singleton<CDLWork>, IInit, IDispose
    {
     private Queue<SDLTaskItem> m_waitItems;
     private readonly object m_object = new object();
    
     public void Init()
      {
      m_waitItems = new KPriorityQueue<int, SDLTaskItem, int>();
     }
    
     public void AddTask(SDLTaskItem taskItem)
     {
       //1.添加任务
         lock (m_object)
         {
             m_waitItems.Enqueue(taskItem);
         }
    
       //添加完任务后,外层update执行刷新不到任务,需要通过直接调用Update才正常
       Update();
     }
    
     //2.外层调用Update刷新任务
     public void Update()
      {
       __OnUpdate();
      }
    
     private void __OnUpdate()
      {
          lock (m_object)
          {
              __AutoAddToExcuteList();
              __StartMultiTask();
          }
      }
    
     private void __StartMultiTask()
      {
        //3.问题:在此发现m_waitItems为空
          if (m_excuteItems.Count <= 0)
          {
              return;
          }
     }
    }

具体原因

  • CMApplication

    csharp
    public class CMApplication : Singleton<CMApplication>, IInit, IDispose
    {
     public void Init()
     {
       ...
         m_dlWork = new CDLWork();
         m_dlWork.Init();
    
         if (null == m_mainThread)
         {
             m_bFlag = true;
             m_mainThread = new Thread(__Run);
             m_mainThread.Start();
         }
     }
     private void __Run()
        {
            while (m_bFlag)
            {
               ...
                m_dlWork.Update();
          ...
                Thread.Sleep(N_MAIN_THREAD_DELAY);
            }
        }
    }
  • Program

    csharp
    static class Program
    {
     static void Main()
      {
        Init();
     }
    
     static void Init()
      {
          //1.系统初始化
          CMApplication.Instance.Init();
    
          //2.Case初始化
          CDLWork.Instance.Init();
      }
    }
  • 使用的地方

    csharp
    CDLWork.Instance.AddTask(task);

这样就明显的看出问题了,外层添加任务使用一个 CDLWork 单例对象,循环调用 CDLWork 的 Update 又是另外一个实例对象,这也就可以解释为啥 update 刷新不到任务了。

总结

  • 自己明显的发现问题,采用回避的方式处理(偷懒),问题终究最后会暴露出来,而导致耗费更多的时间(提醒:以后千万不要用这种态度处理问题,别学我

Released under the MIT License.