C# 线程 - 简介

紧接着进程篇章博客,现在写下一篇线程的博客,不过是简单介绍噢,太深奥的我也不懂啦!!!


什么是线程?

按我个人理解,线程他就像马路,一个车道只能开一辆车(单车道的叫单线程,多车道的叫多线程)。反正就是一个线程只能处理一件事,处理完后才可以去处理其他事情!

线程有什么用?

线程就是给你的程序后台处理任务的,线程越多,处理的效率就越快(就好比如人多力量大一样),当然,也会消耗更多的内存去运行这些工作的线程!

如何定义单线程?

不需要定义,我们平常事就会用得到!
例如控制台输出helloworld、窗体的操作等等。

做一个简单的例子吧!

我们需要一个窗体应用程序,程序中有一个按钮。
为按钮添加单击事件:里面输出1 到 300000.

如下代码:

private void button1_Click(object sender, EventArgs e) {
	text();
}

private void text() {
	for (int i = 0; i < 300000; i++) {
		Console.WriteLine(i);
	}
}

当运行程序,单击按钮后,程序就会在控制台页面输出一到三十万。
在输出的过程中,你的窗体是动不了的,这就出现了窗体“假死状态”,得等到输出完成后,窗体才可以进行其他的操作!(这里就演示不了啦,有兴趣的朋友一定要去试一下)

这是什么原理呢?
其实是我们运行窗体后,就只有一个主线程在进行窗体的运行,当我们点击按钮后,主线程就会紧接着去处理那输出一到三十万那边工作了,进而导致窗体这边没有线程进行运作,所以才出现了“假死”状态!
解决办法就是利用多线程!!!

什么是多线程?

多线程就是两个单线程以上的线程,可以同时处理两个任务!

如何创建多线程?

需要包含命名空间:using System.Threading;

Thread thread = new Thread(text);

text是该线程需要做的工作(一个方法)!

举一个和刚才一样的例子吧!

还是一样的代码,但是这次我们添加了一个线程:

private void button1_Click(object sender, EventArgs e) {
	// 创建一个线程去执行这个方法
	Thread thread = new Thread(text);

	// 标记这个线程准备就绪了,可以随时被执行。
	// 具体什么时候执行这个线程,由CPU决定。
	thread.Start();
}


private void text() {
	for (int i = 0; i < 300000; i++) {
		Console.WriteLine(i);
	}
}

我们通过Thread去创建一个线程thread,通过它去调用函数text,然后执行Start方法,告诉CPU该线程已经准备完毕,随时等待你的启动!

当我们再次运行时,控制台也还是在输出一到三十万,但是窗体却还可以移动,这就是多线程实现的结果!
我们自己创建的新线程去帮我们执行了text()函数,所以主线程还是留在窗体哪里运作,所以可以进行窗体的其他操作!

这就是多线程的功效!!!


我们讲一个知识点

线程有两种:前台线程和后台线程!
1. 前台线程:只有所有的前台线程都关闭才能完成程序关闭;
2. 后台线程:只有所有的前台线程关闭,后台线程自动关闭。

我们新建的线程默认都是前台线程!

设置为后台线程的方法:

// 设置为后台线程
thread.IsBackground = true;

这点是需要注意一下的!!!


我们再讲例子改变一下需求吧!

这次我们不在控制台输出了,而是改成在窗体添加要给TextBox空间,在这里面显示!
这样着我们看看又会有什么问题呢?
在这里插入图片描述

private void button1_Click(object sender, EventArgs e) {
	// 创建一个线程去执行这个方法
	Thread thread = new Thread(text);

	// 标记这个线程准备就绪了,可以随时被执行。
	// 具体什么时候执行这个线程,由CPU决定。
	thread.Start();
}


private void text() {
	for (int i = 0; i < 300000; i++) {
		this.textBox1.Text = i.ToString();
	}
}

运行截图:
在这里插入图片描述
居然报了这样一个错误❌,异常提示太官方化了,我用平常时的华语描述一边:textBox1不是被自己的线程访问,而是被其他线程访问!所以才操作无效。

这也不是不无道理,我们在text函数中使用了textBox1.Text这个控件进行对他自己赋值,但是这个控件又是在主线程创建的,而我们的text函数是在新的线程中调用的,所以就出现了“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”这样的报错!

这是为什么呢?
原因:C# 不允许跨线程调用!

因为我们的程序每次运行时都会进行一次线程的检查,当他检测出来有跨线程调用时,就立即报错了!

解决办法:让程序忽略检查!

我们可以在窗体的Load事件中,加上这句话:

private void Form1_Load(object sender, EventArgs e) {
	// 取消跨线程的访问(检查)
	Control.CheckForIllegalCrossThreadCalls = false;
}

这样子,就可以正常运行啦!
在这里插入图片描述

我们再做一个例子!

这次我们不等它执行完而是直接鼠标点叉×退出窗体,这样子又会抱什么错误呢?
在这里插入图片描述
(要等程序执行一会儿后再点叉×,这个报错就会出来了)

这时报了这个不知道什么鬼的错误。。。

原因是:当我们直接点叉×,主线程关闭了,我们的新线程还没有关闭还在运转,所以就发生了报错!

解决办法就是:当我们点击叉×的那一瞬间,检查新线程是否已经关闭,如果没有关闭,则需要人工关闭!

所以我们得为窗体绑定一个FormClosing事件,在这个事件中我们需要自己手动去关闭新的线程!

使用Abort()函数即可!

private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
	// 主线程关闭后,新线程不为NULL则需手动关闭线程
	if (thread != null) {
		thread.Abort();
	}
}

好了,到了这里线程的知识点也都讲得差不多了,我们下面来做一个线程的小项目吧!

摇奖机

界面如下:
在这里插入图片描述

当我们点击开始按钮后,按钮的文本会变成停止,然后上面三个leible会刷新随机数,直到我们点停止为止!

效果如下:
在这里插入图片描述

我这个我就不细讲了,把代码写下来有兴趣的可以看一看:

*******摇奖机*********/

// 主要是控制随机数
bool isBool = false;

private void btnStart_Click(object sender, EventArgs e) {
            
	if (isBool == false) {
		isBool = true;
		this.btnStart.Text = "停止";
		Thread th = new Thread(Randoms);    // 创建一个线程
		th.IsBackground = true;             // 设置为后台线程
		th.Start();     // 启动线程
	} else {
		isBool = false;
		this.btnStart.Text = "开始";
                
	}
                     
}

private void Randoms() {
	Random random = new Random();   // 实例化随机对象

	// 该循环由按钮控制
	while (isBool) {
		// 随机产生 0 - 9 
		this.label1.Text = random.Next(0, 9).ToString();
		this.label2.Text = random.Next(0, 9).ToString();
		this.label3.Text = random.Next(0, 9).ToString();
	}            
}

下面是全部代码集合:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


/*
 * 前台线程:只有所有的前台线程都关闭才能完成程序关闭;
 * 
 * 后台线程:只有所有的前台线程关闭,后台线程自动关闭。
 */


namespace 线程学习 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        // 线程
        Thread thread;
        private void button1_Click(object sender, EventArgs e) {
            // 创建一个线程去执行这个方法
            thread = new Thread(text);

            // 设置为后台线程
            thread.IsBackground = true;

            // 标记这个线程准备就绪了,可以随时被执行。
            // 具体什么时候执行这个线程,由CPU决定。
            thread.Start();
        }


        private void text() {
            for (int i = 0; i < 300000; i++) {
                //Console.WriteLine(i);
                this.textBox1.Text = i.ToString();
            }
        }

        private void Form1_Load(object sender, EventArgs e) {
            // 取消跨线程的访问(检查)
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            // 主线程关闭后,新线程不为NULL则需手动关闭线程
            if (thread != null) {
                thread.Abort();
            }
        }






        /*******摇奖机*********/

        // 主要是控制随机数
        bool isBool = false;

        private void btnStart_Click(object sender, EventArgs e) {
            
            if (isBool == false) {
                isBool = true;
                this.btnStart.Text = "停止";
                Thread th = new Thread(Randoms);    // 创建一个线程
                th.IsBackground = true;             // 设置为后台线程
                th.Start();     // 启动线程
            } else {
                isBool = false;
                this.btnStart.Text = "开始";
                
            }
                     
        }

        private void Randoms() {
            Random random = new Random();   // 实例化随机对象

            // 该循环由按钮控制
            while (isBool) {
                // 随机产生 0 - 9 
                this.label1.Text = random.Next(0, 9).ToString();
                this.label2.Text = random.Next(0, 9).ToString();
                this.label3.Text = random.Next(0, 9).ToString();
            }            
        }
    }
}

总结:
好了,线程的知识点我懂的也就这些了,说好的简介,也还是写下了那么多,也就这样吧,希望对看到这篇博客的朋友有帮助吧!

  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值