C#winform单线程事例与多线程事例

通过例子编写,用winform编写的,讲解单线程与多线程使用,用于异步加载数据,界面不会卡死,数据在后台默认加载,给用户更好的体验。稍后会附加完整代码。

1、先不用线程,显示一个求和,计算过程中要停留1秒后继续计算。如果不用多线程页面就会卡死,直到计算完成后才会响应。一个button按钮,一个label

C#winform单线程事例与多线程事例

代码如下:

#region 不用线程情况
        private void button1_Click(object sender, EventArgs e)
        {
            //不用线程点击按钮,窗体会卡死,10秒后恢复
            int sum = 0;
            for (int i = 0; i < 10; i++)
            {
                sum = sum + i;
                label3.Text = sum.ToString();
                Thread.Sleep(1000);//休息1秒
            }
        }
        #endregion

2、用单线程进行处理,单独开启一个进线程启动,进行每个2秒钟进行计数显示,并且窗体不会死。界面是一个button 两个 label。

C#winform单线程事例与多线程事例

代码:

#region 多线程中,单独一个线程运行
        private void btnD_Click(object sender, EventArgs e)
        {
            //多线程中,单独一个进程启动,进行每个2秒钟进行计数显示,并且窗体不会死。
            Thread t = new Thread(new ThreadStart(OneThreadSum));//开启线程
            t.IsBackground = true;//附加主线程,主线程关闭后,子线程也跟着关闭,简单理解就是窗体关闭,启动线程也跟着关闭。
            t.Start();
        }
        private void OneThreadSum()
        {
            try
            {
                Invoke(this, delegate
                {
                    //按钮变为灰色 防止按钮多次点击
                    //给控件赋值就需要使用invoke
                    this.btnD.Enabled = false;
                });

                for (int i = 0; i < 10; i++)
                {
                    Invoke(this, delegate
                    {
                        //通过代理赋值,通过这种方式,界面和窗口就不会卡死,窗口先展示出来,然后数据过后加载。
                        //给控件赋值就需要使用invoke
                        label2.Text = i.ToString();
                    });
                    Thread.Sleep(2000);//休息2秒
                }
            }
            catch (Exception ex)
            {

                throw;
            }
            finally
            {
                //给控件赋值就需要使用invoke
                Invoke(this, delegate
                {
                    this.btnD.Enabled = true;
                });
            }

        }
        ///
        /// 在线程中通过代理给控件赋值
        ///
        ///
        ///
        public void Invoke(Control col, MethodInvoker method)
        {
            if (!col.IsHandleCreated) return;//当前控件是否被创建
            if (col.IsDisposed) return;//当前控件是否被销毁
            if (col.InvokeRequired) col.Invoke(method);//是否允许被请求
            else method();
        }
        #endregion

3、模拟餐馆来人吃饭,客人来了点菜是一个线程,客人就餐时一个线程,客人结账时一个线程,一共3个线程,各自处理各自的事情,一个客人名称textbox, 一个客人来了button,一个启动初始化按钮,listbox1 代表点餐记录 ,listbox2 代表就餐记录 ,listbox3代表结账记录 。

C#winform单线程事例与多线程事例

代码:

#region 用多线程 不是单独一个线程,以3个线程为例
        //模拟餐馆来人吃饭,客人来了点菜是一个线程,客人吃饭时一个线程,客人结账时一个线程,一共3个线程

        private void 启动监听线程_Click(object sender, EventArgs e)
        {
            启动监听线程.Enabled = false;//初始化只允许一次,否则会开启很多线程,所以要灰色
            wait1 = new ManualResetEvent(false);//启动信号,等待着。
            t1 = new Thread(new ThreadStart(F1)) { IsBackground = true };
            t1.Start();//初始化线程t1 点餐线程

            wait2 = new ManualResetEvent(false);
            t2 = new Thread(new ThreadStart(F2)) { IsBackground = true };
            t2.Start();//初始化线程t2 用餐线程

            wait3 = new ManualResetEvent(false);
            t3 = new Thread(new ThreadStart(F3)) { IsBackground = true };
            t3.Start();//初始化线程t3 结账线程
        }
        private void 客人来了_Click(object sender, EventArgs e)
        {
            data1.Add(textBox1.Text);//这个时候客人来了,增加到list中。
            wait1.Set();//告诉服务员,客人来了,要开始点餐了。
        }
        private IList data1 = new ArrayList();//存储来客人
        private Thread t1 = null;//点菜线程
        private ManualResetEvent wait1 = null;//信号,相当于服务员,客人来了需要告诉
        private void F1()
        {
            while (true)
            {
                //2秒钟查询一次。
                if (wait1.WaitOne(2000, false))
                {
                    if (data1 == null || data1.Count == 0)
                    {
                        //如果一个人都没有的话,不需要点菜
                        Invoke(this, delegate
                        {
                            listBox1.Items.Add("无客人!");
                        });
                        wait1.Reset();//线程停止,继续等待。
                        continue;//结束本次循环
                    }
                    //程序执行到这里说明有人,客人开始点餐。
                    string r = data1[0] as string;
                    Invoke(this, delegate
                    {
                        listBox1.Items.Add(r + "->开始点餐!");
                    });
                    Thread.Sleep(2000);

                    data2.Add(r);//增加到用餐list中
                    wait2.Set();//告诉可以开始用餐了。

                    data1.RemoveAt(0);//客人从队列中移除
                }
            }
        }

        private IList data2 = new ArrayList();//存储用餐人
        private Thread t2 = null;//用餐线程
        private ManualResetEvent wait2 = null;//信号,用餐信号
        private void F2()
        {
            while (true)
            {
                if (wait2.WaitOne(2000, false))
                {
                    if (data2 == null || data2.Count == 0)
                    {
                        Invoke(this, delegate
                        {
                            listBox2.Items.Add("无用餐人!");
                        });
                        wait2.Reset();
                        continue;
                    }
                    //程序执行到这里说明有人,客人开始用餐。
                    string r = data2[0] as string;

                    Invoke(this, delegate
                    {
                        listBox2.Items.Add(r + "->用餐中...!");
                    });
                    Thread.Sleep(3000);

                    data3.Add(r);//增加到结账的list中
                    wait3.Set();//告诉客人可以开始结账了

                    data2.RemoveAt(0);//客人从队列中移除
                }
            }
        }

        private IList data3 = new ArrayList();//存储结账人
        private Thread t3 = null;//结账线程
        private ManualResetEvent wait3 = null;//结账信号
        private void F3()
        {
            while (true)
            {
                if (wait3.WaitOne(2000, false))
                {
                    if (data3 == null || data3.Count == 0)
                    {
                        Invoke(this, delegate
                        {
                            listBox3.Items.Add("无结账人!");
                        });
                        wait3.Reset();
                        continue;
                    }
                    //程序执行到这里说明有人,客人开始结账。
                    string r = data3[0] as string;

                    Invoke(this, delegate
                    {
                        listBox3.Items.Add(r + "->结账买单!");
                    });
                    Thread.Sleep(4000);

                    data3.RemoveAt(0);//客人从队列中移除
                }
            }
        }

        ///
        /// 在线程中通过代理给控件赋值
        ///
        ///
        ///
        public void Invoke(Control col, MethodInvoker method)
        {
            if (!col.IsHandleCreated) return;//当前控件是否被创建
            if (col.IsDisposed) return;//当前控件是否被销毁
            if (col.InvokeRequired) col.Invoke(method);//是否允许被请求
            else method();
        }

        #endregion

csdn 源码下载链接:https://download.csdn.net/download/njxiaogui/12514492

Original: https://www.cnblogs.com/smile-wei/p/13093729.html
Author: 小东北
Title: C#winform单线程事例与多线程事例

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/539918/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Kubernetes-Service

    1. 简介 kubernets service 是将运行一组pods上的应用程序公开为网络服务的抽象方法。 有了 kubernets service,你就无需修改应用程序即可使用服…

    Java 2023年6月7日
    084
  • 设计模式学习笔记(十五)命令模式及在Spring JdbcTemplate 中的实现

    命令(Command)模式是指将请求封装成为一个对象,使发出请求和执行请求的责任分割开,方便将命令对象进行存储、传递、调用、增加与管理。 也就是将发送者、接收者和调用命令封装成独立…

    Java 2023年6月6日
    089
  • 一份简明的 Base64 原理解析

    书接上回,在 记一个 Base64 有关的 Bug 一文里,我们说到了 Base64 的编解码器有不同实现,交叉使用它们可能引发的问题等等。 这一回,我们来对 Base64 这一常…

    Java 2023年6月5日
    083
  • redis删除缓存时遇到的问题

    一、redis查询key的方式 redis常用两种方式用于key的精确/模糊匹配 1. KEYS pattern keys pattern用于匹配pattern所有key,会返回当…

    Java 2023年6月13日
    0106
  • Yaml学习笔记

    YAML是专门用来写配置文件中,接触最多的是spring boot的配置文件。 基本语法 大小写敏感 使用缩进表示层级关系 缩进时不允许使用Tab键,只允许使用空格。 缩进的空格数…

    Java 2023年6月6日
    083
  • HTML笔记整理–上节

    一、认识WEB 「网页」主要是由 &#x6587;&#x5B57;、 &#x56FE;&#x50CF;和 &#x8D85;&#x94…

    Java 2023年6月7日
    0106
  • Spring @ResponseBody 返回中文乱码问题

    今天在使用spring 的时候,发现中文返回的是乱码。 经过研究发现,主要是@ResponseBody 引起的。主要是由于 @ResponseBody 返回字符串结果的时候,使用了…

    Java 2023年5月30日
    070
  • security学习笔记

    spring security 入门案例 创建springboot工程 引入依赖 org.springframework.boot spring-boot-starter-secu…

    Java 2023年6月9日
    071
  • Spring Cloud OpenFeign 的基本工作原理

    背景 OpenFeign 是 Spring Cloud 家族的一个成员, 它最核心的作用是为 HTTP 形式的 Rest API 提供了非常简洁高效的 RPC 调用方式。 如果说 …

    Java 2023年6月6日
    080
  • 20220808-final关键字

    1. 使用场景: 2. 注意细节: final关键字:可以修饰类、属性、方法和局部变量 1. 使用场景: 当不希望类被继承时,可以使用final修饰类 当不希望父类的某个方法被子类…

    Java 2023年6月15日
    072
  • 【RocketMQ】消息的存储

    Broker对消息的处理 BrokerController初始化的过程中,调用 registerProcessor方法注册了处理器,在注册处理器的代码中可以看到创建了处理消息发送的…

    Java 2023年6月8日
    094
  • Yapi安装配置(CentOs)

    环境要求 nodejs(7.6+)mongodb(2.6+)git 准备工作 清除yum命令缓存 sudo yum clean all 卸载低版本nodejs yum remove…

    Java 2023年6月15日
    067
  • [二分法]求解递增序列中与x最接近元素问题

    在一个非降序列序列中与给定值 x 最接近的元素 第一行包含一个整数 n,为非降序列长度 (1 Original: https://www.cnblogs.com/fordsonli…

    Java 2023年6月5日
    0104
  • 多线程学习

    这个只是简单的学了一下怎么用,几个小demo,没有深入的讲。 1. 线程简介 线程,进程,多线程 并发:同时发生,在一个时间段内执行,不一定是同一时间点 并行:同时执行,在一个时间…

    Java 2023年6月7日
    080
  • Spring Cloud Eureka 服务注册中心(二)

    序言 Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件 它主要包括两个组件:Eureka Server 和 Eureka Client E…

    Java 2023年5月30日
    072
  • Mybatis系列全解(八):Mybatis的9大动态SQL标签你知道几个?提前致女神!

    封面:洛小汐作者:潘潘 2021年,仰望天空,脚踏实地。 这算是春节后首篇 Mybatis 文了~跨了个年感觉写了有半个世纪 … 借着女神节 ヾ(◍°∇°◍)ノ゙提前祝…

    Java 2023年6月13日
    073
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球