C#多线程,基础知识很重要
本文通过介绍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#多线程,基础知识很重要的更多相关文章
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程基础知识笔记(持续更新)
多线程基础知识笔记 一.线程 1.基本概念 程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是 ...
- JAVA多线程基础知识(一)
一. 基础知识 要了解多线程首先要知道一些必要的概念,如进程,线程等等.开发多线程的程序有利于充分的利用系统资源(CPU资源),使你的程序执行的更快,响应更及时. 1. 进程,一般是指程序或者任务的执 ...
- Java基础知识强化之多线程笔记01:多线程基础知识(详见Android(java)笔记61~76)
1. 基础知识: Android(java)学习笔记61:多线程程序的引入 ~ Android(java)学习笔记76:多线程-定时器概述和使用
- Java多线程基础知识总结
2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...
- C#中的多线程 - 基础知识
原文:http://www.albahari.com/threading/ 文章来源:http://blog.gkarch.com/threading/part1.html 1简介及概念 C# 支持通 ...
- C#中的多线程 - 基础知识 z
原文:http://www.albahari.com/threading/ 专题:C#中的多线程 1简介及概念Permalink C# 支持通过多线程并行执行代码,线程有其独立的执行路径,能够与其它线 ...
- Java多线程基础知识例子
一.管理 1.创建线程 Thread public class Main { public static void main(String[] args) { MyThread myThread = ...
- Java多线程基础知识篇
这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...
随机推荐
- Codeforces Beta Round #85 (Div. 1 Only) C (状态压缩或是数学?)
C. Petya and Spiders Little Petya loves training spiders. Petya has a board n × m in size. Each cell ...
- 【中文排序】mysql order by 中文排序
1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决,那么MySQL ...
- php的socket通信【转载】
对TCP/IP.UDP.Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵.那么我想问: 1. 什么是TCP/IP.UDP?2. Soc ...
- 易碎的鸟蛋 概率DP
1007: 易碎的鸟蛋 时间限制: 1 Sec 内存限制: 128 MB提交: 396 解决: 80[提交][状态][讨论版] 题目描述 你们知道吗?西电的跳楼塔上面有一个鸟巢.某SXBK的教授对 ...
- codevs——1742 爬楼梯
1742 爬楼梯 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 小明家外面有一个长长的楼梯,共N阶.小明的 ...
- cakephp2.3.8中何为component
大胆假设,小心求证 记得这句话是以前读高三的时候,一个数学老师(圆头,有点胖胖的老师,不是很记得),经常挂在嘴边的一句话, 对于我们不理解,或者说是无法确定的东西,我们不妨先大胆地去假 ...
- C#如何给Listbox添加右键菜单
1 拖一个ContextMenuStrip控件,然后可以直接在界面上编辑,也可以在FormLoad的时候动态添加 2 把这两个控件关联起来就可以实现listBox1的右键菜单跟ContextMenuS ...
- Cracking the Coding Interview 150题(二)
3.栈与队列 3.1 描述如何只用一个数组来实现三个栈. 3.2 请设计一个栈,除pop与push方法,还支持min方法,可返回栈元素中的最小值.pop.push和min三个方法的时间复杂度必须为O( ...
- EJB之JPA
在前一篇文章中大概了解了EJB是什么?那么接下来就进一步介绍一下它与JPA有什么样的关系?及什么是JPA?JPA怎样用? 一.是什么? 第一次听说JPA是在EJB视屏中,所以一直感觉他们有不解的渊源. ...
- Eclipse Android环境配置
1.离线安装ADT插件,先将ZIP包下载 Help- Install New Software- Add 重启 2.WIndows -Preference设置SDK目录