0%

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

问题描述:

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

问题现象:

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

思考问题 2:

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

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

思考问题 3

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

回顾一下代码

场景代码

  • CDLWork

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    static class Program
    {
    static void Main()
    {
    Init();
    }

    static void Init()
    {
    //1.系统初始化
    CMApplication.Instance.Init();

    //2.Case初始化
    CDLWork.Instance.Init();
    }
    }
  • 使用的地方

    1
    CDLWork.Instance.AddTask(task);

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

总结

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

以上:如发现有问题,欢迎留言指出,我及时更正

如何文章对你有益,请给我买杯豆浆喝