十字星

  • 首页
  • 技术
  • 随笔
  • 瞎折腾
  • 平面设计
  • 文集
  • 留言
  • 其他
    • API测试
  1. 首页
  2. 技术
  3. 正文

针对上一篇《单例模式基类如何初始化子类》中有关线程启动停止的优化

2021-05-29 1092点热度 0人点赞 0条评论

C# 单例模式基类如何初始化子类 这篇文章中涉及到了线程操作,实际使用时发现如果方法Internal_Start()中睡眠时间较长(例如10秒),操作时在10秒内先调用stop再调用start方法时,希望停止的线程无法停止.

研究了后发现是因为使用的状态位是全局变量,再次调用start时,上一次的stop调用被改为false的状态位还未生效又被改回true,导致调用stop时应停止的线程无法终止同时又启动了一个新线程.

我的解决方法是增加两个全局变量,一个int值记录当前是第几次启动线程(从0开始计数,-1表示线程从未启动过),一个bool值链表记录对应第几次启动的线程状态,线程是否停止使用链表中的标志位判断,int值作为线程启动参数传入内部,这样外部改变它的值时不会影响线程内部对该值的调用.优化后的完整父类文件如下

优化后父类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace HuluChajian.ThreadHelper
{
    /// <summary>此单例只能在主线程执行,未做线程安全处理</summary>
    internal class ThreadHelper<T> where T : class
    {
        static T _instance;
        public static T Instance { get { return _instance == null ? _instance = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString()) : _instance; } }

        int _index = -1;
        /// <summary>记录启动过的线程的标志位,当有线程在运行状态时,此列表应只有最后一个元素为true</summary>
        protected List<bool> isStartLst = new List<bool>();

        /// <summary>标识线程是否已经启动,已经启动值为true</summary>
        protected bool isStart = false;

        /// <summary>启动线程</summary>
        public void Start()
        {
            if (isStart) { return; }//已经启动过不能再次启动,直接返回.
            isStart = true;
            _index++;
            isStartLst.Add(isStart);
            StartTop(_index);
        }

        /// <summary>启动时需要调用的自定义方法,需要自行调用线程[一般情况下不重写此方法,重写时需要完全重写此方法,即重写时不可保留 base.StartTop();]</summary>
        protected virtual void StartTop(int index)
        {
            new Thread((o) =>
            {
                while (isStartLst[(int)o])
                {
                    Internal_Start();
                }
            }).Start(index);
        }
        /// <summary>启动的线程需要执行的操作,重写时无需保留 base.Internal_Start();</summary>
        protected virtual void Internal_Start()
        {
            Console.WriteLine("启动父线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);

            Thread.Sleep(1000);//每隔1秒执行一次 
        }

        /// <summary>停止线程</summary>
        public void Stop()
        {
            isStart = false;
            if (_index!=-1) { isStartLst[_index] = false; }
            Internal_Stop();
        }

        /// <summary>停止线程需要调用的自定义方法,重写时无需保留 base.Internal_Stop();</summary>
        protected virtual void Internal_Stop()
        {
            Console.WriteLine("停止父线程");
        }
    }
}

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: C# WinForm
最后更新:2021-06-05

cxw

技术宅,最喜瞎折腾.

点赞
< 上一篇
下一篇 >
最新 热点 随机
最新 热点 随机
git迁移项目中的某个目录到新项目 winform判断设计模式还是运行时模式 C# 中的where T : class, new() 到底是什么意思? 解决安装.NET失败并提示“无法建立到信任根颁发机构的证书链” 关闭.net4.0的http访问默认代理 删除名称最后带空格的文件夹
winform判断设计模式还是运行时模式 C#窗口Form大小设置过小时,始终显示为136*39解决办法 Hyper-V安装无桌面版CentOS 6.5并配置自启动redis服务之二:在虚拟机中安装CentOS 6.5 C# SoundPlayer 波形头已损坏 解决办法 Android Studio 多个真实设备无线调试 关闭.net4.0的http访问默认代理
标签聚合
PHP WordPress CentOS C# WinForm Linux Excel IT 工具 W10
最近评论
admin 发布于 4 年前(01月22日) 使用Andi Dittrich作者的插件Enlighter实现
alex 发布于 4 年前(01月22日) 博主,请问把代码贴到博客里可以复制是怎么实现的

COPYRIGHT © 2021 十字星. ALL RIGHTS RESERVED

Theme Kratos Made By Seaton Jiang