本文通过介绍C#多线程的用法(基础玩法),附加介绍一下WinForm里边跨线程访问UI的方法

如图,就是这么一个简单的界面,每个按钮下面一个方法,分别设置文本框里边的内容,那么,开始吧!

先介绍一下WinForm的线程模型:WinForm 是通过调用Windows API 的GetMessage Or PeekMeeage来处理其他线程发送过来的消息,这些消息存储在系统的一个消息队列中,创建主界面的线程就是主线程(UI线程),UI线程负责消费该消息队列中的消息。

WinForm框架中有一个ISynchronizeInvoke接口,所有的UI元素都继承自该接口,接口中的InvokeRequired属性表示了当前线程是否是创建它的线程,接口中的BeginInvoke or Invoke 负责将消息发送到消息队列,这样UI线程就能够正确的访问它了。

那么,首先看代码片段一:里边就实现了将设置文本框内容的消息发送到了消息队列

private void SetMessage(string message)
{
if (this.txtMsg.InvokeRequired)
{
//BeginInvoke or Invoke 负责将消息发送到消息队列
this.txtMsg.BeginInvoke(new Action<string>((msg) =>
{
this.txtMsg.Text = msg;
}), message);
}
else
{
this.txtMsg.Text = message;
} }

代码片段二Thread:Thread可能是用的最多的了,也是最早的框架里边就有的。这种写法很简单,也很方便,需要提一下的就是IsBackground属性,IsBackground=true表示为后台线程,应用程序退出,哪怕任务没有执行完,也会退出;IsBackground=false表示为前台线程,默认为false,应用程序退出,只要任务还没有执行完,进程就不会结束。

private void btnThread_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
SetMessage("Thread 跨线程访问UI");
});
//IsBackground=true表示为后台线程 应用程序退出 哪怕任务没有执行完 也会退出
//IsBackground=false表示为后台线程 默认为false 应用程序退出 只要任务还没有执行完 进程就不会结束
thread.IsBackground = true;
thread.Start();
}

代码片段三ThreadPool:ThreadPool是微软为了避免开发人员,无节制的使用线程,而提供的一个线程管理类

private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池 是微软为了避免开发人员 无节制的使用线程 而提供的一个线程管理类
ThreadPool.QueueUserWorkItem((obj) =>
{
SetMessage("ThreadPool 跨线程访问UI");
}, null);
}

代码片段四Task:Task有很多的优势,也是后面高版本才推出来的,推荐使用。Task与Thread的区别就是:Task使用的是线程池中的线程,Task较之线程池的优势是:

1.Task支持取消,完成,失败通知等交互性操作

2.Task支持线程执行的先后次序

private void btnTask_Click(object sender, EventArgs e)
{
/* Task与Thread的区别就是:Task使用的是线程池中的线程
* Task较之线程池的优势是:
* 1.Task支持取消,完成,失败通知等交互性操作
* 2.Task支持线程执行的先后次序*/
Task.Factory.StartNew(() =>
{
SetMessage("Task 跨线程访问UI");
}); Task task = new Task(()=> {
SetMessage("Task 跨线程访问UI");
});
task.Start();
}

代码片段五BackgroundWorker:BackgroundWorker内部是通过线程池实现的,通过事件提供了跨线程访问UI的能力,这个做CS开发,是用的最多的,说白了,太好用。

//BackgroundWorker 内部是通过线程池实现的
//BackgroundWorker 通过事件提供了跨线程访问UI的能力
BackgroundWorker _bgw = new BackgroundWorker(); private void btnBackgroundWorker_Click(object sender, EventArgs e)
{
_bgw.WorkerReportsProgress = true;
_bgw.WorkerSupportsCancellation = true;
_bgw.DoWork += _bgw_DoWork; ;
_bgw.ProgressChanged += _bgw_ProgressChanged;
_bgw.RunWorkerCompleted += _bgw_RunWorkerCompleted; if (!_bgw.IsBusy)
{
_bgw.RunWorkerAsync();
}
} private void _bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.txtMsg.Text = "BackgroundWorker 跨线程访问UI";//注意这里是直接访问UI
} private void _bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.txtMsg.Text = e.UserState.ToString();//注意这里是直接访问UI
} private void _bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
_bgw.ReportProgress(i, $"{i}秒");
}
}

代码片段六SynchronizationContext:SynchronizationContext同步上下文在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯,这个在跨线程一次性要更新很多的UI控件的时候,非常的适用。

//SynchronizationContext 在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯
SynchronizationContext _syncContext; private void btnSynchronizationContext_Click(object sender, EventArgs e)
{
_syncContext = SynchronizationContext.Current;
Thread thread = new Thread(() =>
{
if (_syncContext != null)
{
SendOrPostCallback callBack = (obj) =>
{
//在某个子线程里 一次性要更新很多UI控件的时候 用这个方法 很nice
this.txtMsg.Text = "SynchronizationContext 跨线程访问UI";
};
_syncContext.Post(callBack, null);//异步
//_syncContext.Send(callBack, null);//同步
}
});
thread.IsBackground = true;
thread.Start();
}

合并之后的代码为:

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 ThreadChapter
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void btnThread_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
SetMessage("Thread 跨线程访问UI");
});
//IsBackground=true表示为后台线程 应用程序退出 哪怕任务没有执行完 也会退出
//IsBackground=false表示为后台线程 默认为false 应用程序退出 只要任务还没有执行完 进程就不会结束
thread.IsBackground = true;
thread.Start();
} /*
* WinForm 是通过调用Window API 的GetMessage Or PeekMeeage来处理其他线程发送过来的消息,
* 这些消息存储在系统的一个消息队列中,创建主界面的线程就是主线程(UI线程),UI线程负责处理该消息队列
*/ private void SetMessage(string message)
{
if (this.txtMsg.InvokeRequired)
{
//BeginInvoke or Invoke 负责将消息发送到消息队列
this.txtMsg.BeginInvoke(new Action<string>((msg) =>
{
this.txtMsg.Text = msg;
}), message);
}
else
{
this.txtMsg.Text = message;
} } private void btnThreadPool_Click(object sender, EventArgs e)
{
//线程池 是微软为了避免开发人员 无节制的使用线程 而提供的一个线程管理类
ThreadPool.QueueUserWorkItem((obj) =>
{
SetMessage("ThreadPool 跨线程访问UI");
}, null);
} private void btnTask_Click(object sender, EventArgs e)
{
/* Task与Thread的区别就是:Task使用的是线程池中的线程
* Task较之线程池的优势是:
* 1.Task支持取消,完成,失败通知等交互性操作
* 2.Task支持线程执行的先后次序*/
Task.Factory.StartNew(() =>
{
SetMessage("Task 跨线程访问UI");
});
} //BackgroundWorker 内部是通过线程池实现的
//BackgroundWorker 通过事件提供了跨线程访问UI的能力
BackgroundWorker _bgw = new BackgroundWorker(); private void btnBackgroundWorker_Click(object sender, EventArgs e)
{
_bgw.WorkerReportsProgress = true;
_bgw.WorkerSupportsCancellation = true;
_bgw.DoWork += _bgw_DoWork; ;
_bgw.ProgressChanged += _bgw_ProgressChanged;
_bgw.RunWorkerCompleted += _bgw_RunWorkerCompleted; if (!_bgw.IsBusy)
{
_bgw.RunWorkerAsync();
}
} private void _bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.txtMsg.Text = "BackgroundWorker 跨线程访问UI";//注意这里是直接访问UI
} private void _bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.txtMsg.Text = e.UserState.ToString();//注意这里是直接访问UI
} private void _bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
_bgw.ReportProgress(i, $"{i}秒");
}
} //SynchronizationContext 在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯
SynchronizationContext _syncContext; private void btnSynchronizationContext_Click(object sender, EventArgs e)
{
_syncContext = SynchronizationContext.Current;
Thread thread = new Thread(() =>
{
if (_syncContext != null)
{
SendOrPostCallback callBack = (obj) =>
{
//在某个子线程里 一次性要更新很多UI控件的时候 用这个方法 很nice
this.txtMsg.Text = "SynchronizationContext 跨线程访问UI";
};
_syncContext.Post(callBack, null);//异步
//_syncContext.Send(callBack, null);//同步
}
});
thread.IsBackground = true;
thread.Start();
}
}
}

C#多线程,基础知识很重要的更多相关文章

  1. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  2. Java多线程基础知识笔记(持续更新)

    多线程基础知识笔记 一.线程 1.基本概念 程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是 ...

  3. JAVA多线程基础知识(一)

    一. 基础知识 要了解多线程首先要知道一些必要的概念,如进程,线程等等.开发多线程的程序有利于充分的利用系统资源(CPU资源),使你的程序执行的更快,响应更及时. 1. 进程,一般是指程序或者任务的执 ...

  4. Java基础知识强化之多线程笔记01:多线程基础知识(详见Android(java)笔记61~76)

    1. 基础知识: Android(java)学习笔记61:多线程程序的引入    ~    Android(java)学习笔记76:多线程-定时器概述和使用 

  5. Java多线程基础知识总结

    2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...

  6. C#中的多线程 - 基础知识

    原文:http://www.albahari.com/threading/ 文章来源:http://blog.gkarch.com/threading/part1.html 1简介及概念 C# 支持通 ...

  7. C#中的多线程 - 基础知识 z

    原文:http://www.albahari.com/threading/ 专题:C#中的多线程 1简介及概念Permalink C# 支持通过多线程并行执行代码,线程有其独立的执行路径,能够与其它线 ...

  8. Java多线程基础知识例子

    一.管理 1.创建线程 Thread public class Main { public static void main(String[] args) { MyThread myThread = ...

  9. Java多线程基础知识篇

    这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...

随机推荐

  1. HDU 5024

    题目大意: 在2个图上显示为'.'的位置建两座房间,保证这两间房子中间只转一个90度的弯,可以斜着走,问能建成房子的最远的路程长度为多少 暴力枚举 因为有8个方向,但横竖走和斜着走是不会产生90度角的 ...

  2. [K/3Cloud] 代码中设置某个字段必录

    Control ctl = this.GetControl(fieldKey); FieldEditor editCtl = ctl as FieldEditor; if (editCtl != nu ...

  3. 【Eclipse+IntelliJ反编译】Eclipse/IntelliJ IDEA反编译查看源码及注释

    怎么用IDE查看第三方jar包的源码和注释,IntelliJ IDEA自带反编译器,Eclipse装个插件即可,不能看注释就麻烦了,总不能去找API文档吧,现在终于掌握了,下面给出解决方案,供大家参考 ...

  4. android中后一个activity传值给前一个activity的实现

    前一个activity跳转到后一个activity设置code: Intent intent=new Intent(MainActivity.this,ActivityTwo.class); star ...

  5. 浅识MySQL

    MySQL常用语句 #操作数据库 ##创建数据库 CREATE DATABASE `dbName`; ##切换数据库 USE `dbName`; ##查看所有数据库 SHOW DATABASES; # ...

  6. hadoop(1)入门

    hadoop入门(一)   一.概述 1.什么是hadoop hadoop不仅是一个用于存储分布式文件系统,还是设计用来在有通用计算设备组成的大型集群上执行的分布式应用的基础框架. hadoop框架最 ...

  7. mybatis resultmap标签type属性什么意思

    mybatis resultmap标签type属性什么意思? :就表示被转换的对象啊,被转换成object的类型啊 <resultMap id="BaseResultMap" ...

  8. 作为一名CEO

    你 不能怕得罪人 不能奢望完成工作的时候 有太多的愉悦感 你 必须要去做左右为难但左右亦可的 操蛋决策 你 得脸皮够厚 肚囊儿宽超 什么事情都能快速消化 哪怕 是 一坨屎 你 还得 决不放弃 永不言败 ...

  9. 【C++/数据结构】单链表的基本操作

    #pragma once #ifndef _CLIST_H_ #define _CLIST_H_ #include <iostream> #include <assert.h> ...

  10. 解决Vue打包后背景图片路径错误问题

    1.原因解析 当用vue-cli自动构建项目后,有两种运行方法,分别是: npm run dev : 提供一个开发的环境,自动热更新,资源使用绝对路径,所以可以正常看到背景图片. npm run bu ...