Skip to content
On this page

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

问题描述:

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

问题现象:

  • 问题 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.