C#---多线程

来源:互联网 发布:ch341a编程器教程 编辑:程序博客网 时间:2024/05/17 07:02

C#---多线程


线程介绍:前台线程和后台线程。

  • 前台线程:只有所有的前台线程都关闭才能完成程序关闭。
  • 后台线程:只要所有的前台线程结束,后台线程自动结束。
在.NET下,不允许跨线程的访问。


1、创建一个WINFORM窗体程序,在窗体上添加一个按钮控件和TextBox控件。并为按钮添加一个事件。

修改Form1.cs的代码:


using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace 多线程{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            Test(); //调用自定义Test()函数        }        private void Test()//在控制台打印输出10000个数        {            for (int i = 0; i < 10000;i++ )            {                Console.WriteLine(i);            }        }    }}

运行结果:可以通过“调试菜单---->窗口---->输出”查看输出结果。

注意:但有一个问题单击按钮后,数字未打印完10000个数字,FORM窗体不能移动。并且未打印完成不能关闭窗体。

(1)单线程问题:点击按钮后,主线程去运行Test()函数进行打印输出。本来主线程是用于窗体的运行。

2、使用多线程方法一

修改Form1.cs的代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading; //添加线程命名空间(首先选择,快捷键:alt+shift+F10)namespace 多线程{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            //创建一个线程去执行这个方法            Thread th = new Thread(Test);   //用线程调用Test()方法            th.Start();//标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程由CPU决定。
  
 th.IsBackground = true; //将线程设置为后台线程        }        private void Test()        {            for (int i = 0; i < 10000;i++ )            {                Console.WriteLine(i);            }        }    }}

运行结果:

未设置为后台线程前:单击按钮后,数字未打印完10000个数字,FORM窗体可以进行移动。并且未打印完成可以关闭窗体。但程序依旧在运行。

设置为后台线程后:单击按钮后,数字未打印完10000个数字,FORM窗体可以进行移动。并且未打印完成可以关闭窗体。关闭窗体的同时程序退出运行。

3、使用多线程方法二

(1)把打印的值传给TextBox控件显示

修改Form1.cs的代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading; //添加线程命名空间(首先选择快捷键:alt+shift+F10)namespace 多线程{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            //创建一个线程去执行这个方法            Thread th = new Thread(Test);   //用线程调用Test()方法            th.Start();//标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程由CPU决定。            th.IsBackground = true; //将线程设置为后台线程        }        private void Test()        {            for (int i = 0; i < 10000;i++ )            {                                textBox1.Text = i.ToString();   //把打印的值传给TextBox控件显示            }        }    }}

运行结果:

运行会抛出异常。

主线程创建了窗体,新创建的线程调用Test()方法,方法中用到了textBox控件,即新建线程要调用主线程的资源报错。


(2)为FORM添加Load事件,并修改Form1.cs的代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading; //添加线程命名空间(首先选择快捷键:alt+shift+F10)namespace 多线程{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            //创建一个线程去执行这个方法            Thread th = new Thread(Test);   //用线程调用Test()方法            th.Start();//标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程由CPU决定。            th.IsBackground = true;//将线程设置为后台线程        }        private void Test()        {            for (int i = 0; i < 10000;i++ )            {                                textBox1.Text = i.ToString();   //把打印的值传给TextBox控件显示            }        }        private void Form1_Load(object sender, EventArgs e)        {            //取消跨线程的访问----            Control.CheckForIllegalCrossThreadCalls = false;    //不捕获对错误线程的调用        }    }}

运行结果:


但是在关闭程序时,偶尔也会抛出异常。

主要原因:关闭程序时,新线程没有马上关闭,新建线程仍然在访问文本框控件;但是主线程已经关闭,文本框已经被释放掉不存在了,所以抛出异常。


解决方法:

为窗体关闭添加“FormClosing”事件,并修改Form1.cs的代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading; //添加线程命名空间(首先选择快捷键:alt+shift+F10)namespace 多线程{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        Thread th;//为了Form1_FormClosing()访问到th        private void button1_Click(object sender, EventArgs e)        {            //创建一个线程去执行这个方法            th = new Thread(Test);   //用线程调用Test()方法            th.Start();//标记这个线程准备就绪了,可以随时被执行。具体什么时候执行这个线程由CPU决定。            th.IsBackground = true;//将线程设置为后台线程        }        private void Test()        {            for (int i = 0; i < 10000;i++ )            {                                textBox1.Text = i.ToString();   //把打印的值传给TextBox控件显示            }        }        private void Form1_Load(object sender, EventArgs e)        {            //取消跨线程的访问----            Control.CheckForIllegalCrossThreadCalls = false;    //不捕获对错误线程的调用        }        private void Form1_FormClosing(object sender, FormClosingEventArgs e)        {            //当点击关闭窗体的时候,先判断新线程是否为null(新线程已经关闭)            if (th!=null)                 {                th.Abort(); //结束这个线程            }        }           }}

关闭可以正常;关闭后新建线程没法再被重新启动,即线程被Abort()后不能被重新Start()。


4、线程静态方法使用

Thread.Sleep(1)静态方法,可以使当前线程停止一段时间运行。

(1)新建一个C#控制台程序,其代码为:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; //线程命名空间


namespace 多线程静态方法
{
    class Program
    {
        static void Main(string[] args)
        {
            //线程静态方法
            Thread.Sleep(3000); //延时3000毫秒即3秒
            Console.WriteLine("hello world");
            Console.ReadLine();
        }
    }
}

运行结果:

延时3秒后,控制台才打印出hello world.


1 0