- 浏览: 207616 次
- 性别:
- 来自: 成都
-
文章分类
- 全部博客 (231)
- C++学习 (41)
- vc学习 (25)
- vc异常 (4)
- Flex (2)
- Ext (0)
- java学习笔记 (15)
- mysql学习笔记 (1)
- ibatis学习笔记 (7)
- struts1学习笔记 (1)
- hibernate学习笔记 (3)
- javascript学习笔记 (8)
- eclipse快捷键 (2)
- 英语学习 (1)
- cmd (1)
- eclipse 配置 (2)
- 其他 (4)
- JAVASE (34)
- firefox (1)
- linux (8)
- Apache (6)
- cms (22)
- jsuc (10)
- html (3)
- css (1)
- 作图 (2)
- vs2012 (2)
- 编码转换 (12)
- work_unicode (1)
- work_webbrowser (1)
- work_trade_quotes_login (1)
- c#学习 (38)
- wpf学习 (31)
- wpf快速学习 (1)
- VB学习 (1)
- NSIS (4)
- log4cpp (3)
- 学习web (1)
- 经验 (1)
- c_汇编 (1)
最新评论
线程之间的通讯---SynchronizationContext(转载)
理解SynchronizationContext
________________________________________
SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文。 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。同步模型的提供程序可以扩展此类并为这些方法提供自己的实现。(来自MSDN)
简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色。另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。
这里你可能有个问题:对于UI线程来说,是如何将SynchronizationContext这个对象附加到线程上的呢?!OK,我们先从下面的代码开始,
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// let's check the context here
var context = SynchronizationContext.Current;
if (context == null)
MessageBox.Show("No context for this thread");
else
MessageBox.Show("We got a context");
// create a form
Form1 form = new Form1();
// let's check it again after creating a form
context = SynchronizationContext.Current;
if (context == null)
MessageBox.Show("No context for this thread");
else
MessageBox.Show("We got a context");
if (context == null)
MessageBox.Show("No context for this thread");
Application.Run(new Form1());
}
运行结果:
1、No context for this thread
2、We got a context
从运行结果来看,在Form1 form = new Form1()之前,SynchronizationContext对象是为空,而当实例化Form1窗体后,SynchronizationContext对象就被附加到这个线程上了。所以可以得出答案了:当Control对象被创建的同时,SynchronizationContext对象也会被创建并附加到线程上。
好的,我们既然已经基本了解了SynchronizationContext,接下来的事情就是使用它了!
如何使用SynchronizationContext
________________________________________
应用程序有两个线程:线程A和线程B,不过线程B比较特殊,它属于UI线程,当这两个线程同时运行的时候,线程A有个需求:"修改UI对象的属性",这时候如果你是线程A,你会如何去完成需求呢?!
第一种方式:
在线程A上面直接去操作UI对象,这是线程B说:"线程A,你真xx,你不知道我的特殊嘛!",然后直接抛给线程A一个异常信息,线程A得到异常后,一脸的无辜和无奈.....!
第二种方式:
InvokeRequired?!是的,当然没问题。(解释下,InvokeRequired属性是每个Control对象都具有的属性,它会返回true和false,当是true的时候,表示它在另外一个线程上面,这是必须通过Invoke,BeginInvoke这些方法来调用更新UI对象的方法,当是false的时候,有两种情况,1:位于当前线程上面,可以通过直接去调用修改UI对象的方法,2:位于不同的线程上,不过控件或窗体的句柄不存在。对于句柄是否存在的判断,可以通过IsHandleCreated来获取,如果句柄不存在,是不能调用Invoke...这些方法的,这时候你必须等待句柄的创建)
通过InvokeRequired的实现方式如下:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
public class MyFormControl : Form
{
public delegate void AddListItem(String myString);
public AddListItem myDelegate;
private Button myButton;
private Thread myThread;
private ListBox myListBox;
public MyFormControl()
{
myButton = new Button();
myListBox = new ListBox();
myButton.Location = new Point(72, 160);
myButton.Size = new Size(152, 32);
myButton.TabIndex = 1;
myButton.Text = "Add items in list box";
myButton.Click += new EventHandler(Button_Click);
myListBox.Location = new Point(48, 32);
myListBox.Name = "myListBox";
myListBox.Size = new Size(200, 95);
myListBox.TabIndex = 2;
ClientSize = new Size(292, 273);
Controls.AddRange(new Control[] {myListBox,myButton});
Text = " 'Control_Invoke' example ";
myDelegate = new AddListItem(AddListItemMethod);
}
static void Main()
{
MyFormControl myForm = new MyFormControl();
myForm.ShowDialog();
}
public void AddListItemMethod(String myString)
{
myListBox.Items.Add(myString);
}
private void Button_Click(object sender, EventArgs e)
{
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
private void ThreadFunction()
{
MyThreadClass myThreadClassObject = new MyThreadClass(this);
myThreadClassObject.Run();
}
}
public class MyThreadClass
{
MyFormControl myFormControl1;
public MyThreadClass(MyFormControl myForm)
{
myFormControl1 = myForm;
}
String myString;
public void Run()
{
for (int i = 1; i <= 5; i++)
{
myString = "Step number " + i.ToString() + " executed";
Thread.Sleep(400);
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle with
// the specified list of arguments.
myFormControl1.Invoke(myFormControl1.myDelegate,
new Object[] {myString});
}
}
}
不过这里存在一个有争论的地方:这种方式必须通过调用Control的Invoke方法来实现,这就是说调用的地方必须有一个Control的引用存在。
看下MyThreadClass类,这个类中就存在MyFormControl的引用对象。其实如果这个类放在这里是没有任务不妥之处的,但是如果把MyThreadClass类放在业务层,这时候问题就出现了,从设计角度来说,业务层是不允许和UI有任何关系,所以MyFormControl的引用对象绝对不能存在于MyThreadClass类,但是不让它存在,更新UI控件的需求就满足不了,这种情况下,我们如何做到一种最佳方案呢!?
第三种方式:
本文的主角:SynchronizationContext登场了。解释之前,先让下面的代码做下铺垫,
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void mToolStripButtonThreads_Click(object sender, EventArgs e)
{
// let's see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id);
// grab the sync context associated to this
// thread (the UI thread), and save it in uiContext
// note that this context is set by the UI thread
// during Form creation (outside of your control)
// also note, that not every thread has a sync context attached to it.
SynchronizationContext uiContext = SynchronizationContext.Current;
// create a thread and associate it to the run method
Thread thread = new Thread(Run);
// start the thread, and pass it the UI context,
// so this thread will be able to update the UI
// from within the thread
thread.Start(uiContext);
}
private void Run(object state)
{
// lets see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("Run thread: " + id);
// grab the context from the state
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 0; i < 1000; i++)
{
// normally you would do some code here
// to grab items from the database. or some long
// computation
Thread.Sleep(10);
// use the ui context to execute the UpdateUI method,
// this insure that the UpdateUI method will run on the UI thread.
uiContext.Post(UpdateUI, "line " + i.ToString());
}
}
/// <summary>
/// This method is executed on the main UI thread.
/// </summary>
private void UpdateUI(object state)
{
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("UpdateUI thread:" + id);
string text = state as string;
mListBox.Items.Add(text);
}
}
运行结果:
mToolStripButtonThreads_Click thread: 10
Run thread: 3
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
(x1000 times)
程序首先在Form1窗体的mToolStripButtonThreads_Click事件中,获取当前的SynchronizationContext对象,然后启动另外一个线程,并且将SynchronizationContext对象传递给启动的线程,启动的线程通过SynchronizationContext对象的Post方法来调用一个委托方法UpdateUI,因为UpdateUI是执行在主UI线程上的,所以可以通过它来修改UI上对象的信息。
怎么样!不错吧,现在我们可以把Control引用给抛弃了,哈哈!
如果你去查下MSDN,会发现SynchronizationContext还有一个Send方法,Send和Post有什么区别?
Send VS Post,以及异常处理
________________________________________
首先看下异常处理的情况
private void Run(object state)
{
// let's see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("Run thread: " + id);
// grab the context from the state
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 0; i < 1000; i++)
{
Trace.WriteLine("Loop " + i.ToString());
// normally you would do some code here
// to grab items from the database. or some long
// computation
Thread.Sleep(10);
// use the ui context to execute the UpdateUI method, this insure that the
// UpdateUI method will run on the UI thread.
try
{
uiContext.Send(UpdateUI, "line " + i.ToString());
}
catch (Exception e)
{
Trace.WriteLine(e.Message);
}
}
}
/// <summary>
/// This method is executed on the main UI thread.
/// </summary>
private void UpdateUI(object state)
{
throw new Exception("Boom");
}
当你运行的时候, 你可能希望在UI线程上面去抛出,但是结果往往出忽你的意料,异常信息都在Run方法的线程上被捕获了。这时候你可能想问:WHY?!
解释之前,我们先看下,Send VS Post的结果:
Send 方法启动一个同步请求以发送消息
Post 方法启动一个异步请求以发送消息。
哈哈,异常处理的答案迎韧而解了吧!
今天就写到这里吧,下一篇和大家讨论下SynchronizationContext是否在所有线程中都适用...
理解SynchronizationContext
________________________________________
SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文。 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。同步模型的提供程序可以扩展此类并为这些方法提供自己的实现。(来自MSDN)
简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色。另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。
这里你可能有个问题:对于UI线程来说,是如何将SynchronizationContext这个对象附加到线程上的呢?!OK,我们先从下面的代码开始,
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// let's check the context here
var context = SynchronizationContext.Current;
if (context == null)
MessageBox.Show("No context for this thread");
else
MessageBox.Show("We got a context");
// create a form
Form1 form = new Form1();
// let's check it again after creating a form
context = SynchronizationContext.Current;
if (context == null)
MessageBox.Show("No context for this thread");
else
MessageBox.Show("We got a context");
if (context == null)
MessageBox.Show("No context for this thread");
Application.Run(new Form1());
}
运行结果:
1、No context for this thread
2、We got a context
从运行结果来看,在Form1 form = new Form1()之前,SynchronizationContext对象是为空,而当实例化Form1窗体后,SynchronizationContext对象就被附加到这个线程上了。所以可以得出答案了:当Control对象被创建的同时,SynchronizationContext对象也会被创建并附加到线程上。
好的,我们既然已经基本了解了SynchronizationContext,接下来的事情就是使用它了!
如何使用SynchronizationContext
________________________________________
应用程序有两个线程:线程A和线程B,不过线程B比较特殊,它属于UI线程,当这两个线程同时运行的时候,线程A有个需求:"修改UI对象的属性",这时候如果你是线程A,你会如何去完成需求呢?!
第一种方式:
在线程A上面直接去操作UI对象,这是线程B说:"线程A,你真xx,你不知道我的特殊嘛!",然后直接抛给线程A一个异常信息,线程A得到异常后,一脸的无辜和无奈.....!
第二种方式:
InvokeRequired?!是的,当然没问题。(解释下,InvokeRequired属性是每个Control对象都具有的属性,它会返回true和false,当是true的时候,表示它在另外一个线程上面,这是必须通过Invoke,BeginInvoke这些方法来调用更新UI对象的方法,当是false的时候,有两种情况,1:位于当前线程上面,可以通过直接去调用修改UI对象的方法,2:位于不同的线程上,不过控件或窗体的句柄不存在。对于句柄是否存在的判断,可以通过IsHandleCreated来获取,如果句柄不存在,是不能调用Invoke...这些方法的,这时候你必须等待句柄的创建)
通过InvokeRequired的实现方式如下:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
public class MyFormControl : Form
{
public delegate void AddListItem(String myString);
public AddListItem myDelegate;
private Button myButton;
private Thread myThread;
private ListBox myListBox;
public MyFormControl()
{
myButton = new Button();
myListBox = new ListBox();
myButton.Location = new Point(72, 160);
myButton.Size = new Size(152, 32);
myButton.TabIndex = 1;
myButton.Text = "Add items in list box";
myButton.Click += new EventHandler(Button_Click);
myListBox.Location = new Point(48, 32);
myListBox.Name = "myListBox";
myListBox.Size = new Size(200, 95);
myListBox.TabIndex = 2;
ClientSize = new Size(292, 273);
Controls.AddRange(new Control[] {myListBox,myButton});
Text = " 'Control_Invoke' example ";
myDelegate = new AddListItem(AddListItemMethod);
}
static void Main()
{
MyFormControl myForm = new MyFormControl();
myForm.ShowDialog();
}
public void AddListItemMethod(String myString)
{
myListBox.Items.Add(myString);
}
private void Button_Click(object sender, EventArgs e)
{
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
private void ThreadFunction()
{
MyThreadClass myThreadClassObject = new MyThreadClass(this);
myThreadClassObject.Run();
}
}
public class MyThreadClass
{
MyFormControl myFormControl1;
public MyThreadClass(MyFormControl myForm)
{
myFormControl1 = myForm;
}
String myString;
public void Run()
{
for (int i = 1; i <= 5; i++)
{
myString = "Step number " + i.ToString() + " executed";
Thread.Sleep(400);
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle with
// the specified list of arguments.
myFormControl1.Invoke(myFormControl1.myDelegate,
new Object[] {myString});
}
}
}
不过这里存在一个有争论的地方:这种方式必须通过调用Control的Invoke方法来实现,这就是说调用的地方必须有一个Control的引用存在。
看下MyThreadClass类,这个类中就存在MyFormControl的引用对象。其实如果这个类放在这里是没有任务不妥之处的,但是如果把MyThreadClass类放在业务层,这时候问题就出现了,从设计角度来说,业务层是不允许和UI有任何关系,所以MyFormControl的引用对象绝对不能存在于MyThreadClass类,但是不让它存在,更新UI控件的需求就满足不了,这种情况下,我们如何做到一种最佳方案呢!?
第三种方式:
本文的主角:SynchronizationContext登场了。解释之前,先让下面的代码做下铺垫,
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void mToolStripButtonThreads_Click(object sender, EventArgs e)
{
// let's see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id);
// grab the sync context associated to this
// thread (the UI thread), and save it in uiContext
// note that this context is set by the UI thread
// during Form creation (outside of your control)
// also note, that not every thread has a sync context attached to it.
SynchronizationContext uiContext = SynchronizationContext.Current;
// create a thread and associate it to the run method
Thread thread = new Thread(Run);
// start the thread, and pass it the UI context,
// so this thread will be able to update the UI
// from within the thread
thread.Start(uiContext);
}
private void Run(object state)
{
// lets see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("Run thread: " + id);
// grab the context from the state
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 0; i < 1000; i++)
{
// normally you would do some code here
// to grab items from the database. or some long
// computation
Thread.Sleep(10);
// use the ui context to execute the UpdateUI method,
// this insure that the UpdateUI method will run on the UI thread.
uiContext.Post(UpdateUI, "line " + i.ToString());
}
}
/// <summary>
/// This method is executed on the main UI thread.
/// </summary>
private void UpdateUI(object state)
{
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("UpdateUI thread:" + id);
string text = state as string;
mListBox.Items.Add(text);
}
}
运行结果:
mToolStripButtonThreads_Click thread: 10
Run thread: 3
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
(x1000 times)
程序首先在Form1窗体的mToolStripButtonThreads_Click事件中,获取当前的SynchronizationContext对象,然后启动另外一个线程,并且将SynchronizationContext对象传递给启动的线程,启动的线程通过SynchronizationContext对象的Post方法来调用一个委托方法UpdateUI,因为UpdateUI是执行在主UI线程上的,所以可以通过它来修改UI上对象的信息。
怎么样!不错吧,现在我们可以把Control引用给抛弃了,哈哈!
如果你去查下MSDN,会发现SynchronizationContext还有一个Send方法,Send和Post有什么区别?
Send VS Post,以及异常处理
________________________________________
首先看下异常处理的情况
private void Run(object state)
{
// let's see the thread id
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("Run thread: " + id);
// grab the context from the state
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 0; i < 1000; i++)
{
Trace.WriteLine("Loop " + i.ToString());
// normally you would do some code here
// to grab items from the database. or some long
// computation
Thread.Sleep(10);
// use the ui context to execute the UpdateUI method, this insure that the
// UpdateUI method will run on the UI thread.
try
{
uiContext.Send(UpdateUI, "line " + i.ToString());
}
catch (Exception e)
{
Trace.WriteLine(e.Message);
}
}
}
/// <summary>
/// This method is executed on the main UI thread.
/// </summary>
private void UpdateUI(object state)
{
throw new Exception("Boom");
}
当你运行的时候, 你可能希望在UI线程上面去抛出,但是结果往往出忽你的意料,异常信息都在Run方法的线程上被捕获了。这时候你可能想问:WHY?!
解释之前,我们先看下,Send VS Post的结果:
Send 方法启动一个同步请求以发送消息
Post 方法启动一个异步请求以发送消息。
哈哈,异常处理的答案迎韧而解了吧!
今天就写到这里吧,下一篇和大家讨论下SynchronizationContext是否在所有线程中都适用...
发表评论
-
byte数组直接输出
2016-07-19 11:38 1258byte数组直接输出 BitConverter.ToStrin ... -
wfi:WindowsFormsHost焦点设置
2016-07-05 17:56 589<wfi:WindowsFormsHost> ... -
x:Name
2016-04-25 10:44 462由于“Dameer”是在同一程序集中实现的,您必须设置 x:N ... -
WindowsFormsHost的使用注意
2016-04-25 10:24 1372一使用 1 引用 2 xmlns:wfi ="clr ... -
TextBox滚动条
2016-04-22 16:51 670<TextBox Grid.Row="1& ... -
TextBlock滚动条
2016-04-22 16:49 463<ScrollViewer Name="s ... -
C#_WPF_WPF用户控件库
2016-04-12 11:37 818新建项目》window桌面》WPF用户控件库 -
DependencyProperty.UnsetValue_WPF涉及到资源的嵌套引用,被引用的资源要定义在引用的资源前面
2015-10-27 15:09 2046错误 1 “{DependencyProperty.Unset ... -
string格式的日期时间字符串转为DateTime类型
2015-08-05 14:22 974string格式的日期时间字符串转为DateTime类型 / ... -
checkbox
2015-07-28 17:18 566private void Chec ... -
自定义DataGrid样式
2015-06-26 22:03 757<ResourceDictionary xmlns=&q ... -
x:Name x:Key Name区别
2015-06-25 15:40 613x:Name x:Key Name区别 1、x:Key 只 ... -
work_代码添加
2015-06-23 17:15 517<UserControl x:Class=" ... -
FindName和VisualTreeHelper
2015-06-19 13:23 766int iCount = this.dataGridCan ... -
理解WPF中的视觉树和逻辑树(转载)
2015-06-19 13:00 606理解WPF中的视觉树和逻辑树 理解WPF中的 ... -
理解WPF中的视觉树和逻辑树(转载)
2015-06-19 12:58 1716理解WPF中的视觉树和逻 ... -
GetEnumerator
2015-06-19 12:39 666IEnumerator enumerator = this ... -
资源文件获取配置
2015-06-18 16:03 378object obj = Application.Curren ... -
Pack URI
2015-06-18 15:41 698主要用来定位 资源文 ... -
wpf学习之ObservableCollection<T>相关知识
2015-04-23 11:10 3322本篇学习了ObservableCollection<T& ...
相关推荐
子线程访问界面线程的资源会产生跨线程调用的错误,虽然可以通过设置CheckForIllegalCrossThreadCalls来避免此错误但是往往会产生新的问题,使用界面的线程的InvokeRequired或者SynchronizationContext都可以解决此...
本文将详细探讨如何在WinForm应用中实现在后台线程与UI线程之间的通信,并确保UI更新的安全。 首先,理解线程的概念至关重要。在多线程编程中,主线程通常是创建UI并处理用户交互的线程,而后台线程则用于执行耗时...
- **SynchronizationContext**:为异步回调提供自定义的上下文,确保回调在正确的线程上执行。 了解并熟练掌握这些知识点,有助于编写出高效、稳定的多线程C#应用程序。通过阅读《C# 多线程.pdf》这样的资料,可以...
线程同步是多线程编程中的关键概念,它确保了在并发执行的线程之间正确地协调资源访问和执行顺序,以避免数据竞争和死锁等问题。在C#中,线程同步可以通过多种方式实现,包括锁、线程安全的类、中断和终止、线程状态...
SynchronizationContext是.NET Framework提供的一种上下文同步机制,它可以跟踪当前线程,确保回调方法在正确的线程上执行。在WinForms应用中,Application.Current.SynchronizationContext可用于获取UI线程的上...
- SynchronizationContext:.NET框架提供了一个抽象类SynchronizationContext,可以用来协调线程间的通信,特别是UI线程与工作线程之间的交互。 - BackgroundWorker:这是一个设计模式,用于在后台线程执行长时间...
SynchronizationContext类在System.Threading命名空间下,提供了不带同步的自由线程上下文。Post方法签名如下: ```csharp public virtual void Post(SendOrPostCallback d, Object state) ``` 我们可以使用...
`Understanding-the-SynchronizationContext-in-NET-wi.pdf`和`Tasks.zip`可能包含了更深入的案例研究和示例代码,可以帮助你更好地理解和应用`SynchronizationContext`。通过阅读这些资源,你可以学习到如何在实际...
- **线程同步上下文**:主线程与子线程之间的交互,如UI更新,需要考虑同步上下文,通常使用`SynchronizationContext`类。 2. **线程互斥**: - **Mutex对象**:`Mutex`类用于控制对共享资源的访问,实现线程间的...
可以保存主线程的`SynchronizationContext`,并在后台线程中使用它来发送消息回主线程,执行UI更新。例如: ```csharp SynchronizationContext context = SynchronizationContext.Current; // 后台线程中 ...
开发者可以在创建新线程时保存当前的`SynchronizationContext`,然后在需要跨线程调用时使用它。例如: ```csharp SynchronizationContext context = SynchronizationContext.Current; // 创建新线程 new Thread...
在C#编程中,多线程是一个核心概念,它允许程序同时执行多个任务,从而提高应用程序的效率和响应性。本教程将引导你轻松入门C#中的多线程,...然而,多线程编程也带来了复杂性,理解线程之间的交互和同步是至关重要的。
3. 使用`System.Windows.Forms.Application.Run`或`System.Threading.SynchronizationContext`来处理消息循环,以便在STA线程上接收和处理消息。 4. 通过消息队列或者回调函数来在不同线程间通信,模拟多线程的协作...
在跨线程调用控件时,我们必须使用委托作为数据传递的载体,因为它们可以安全地在多个线程之间传递方法调用。委托本质上是类型安全的函数指针,允许我们传递方法作为参数或在事件处理中使用。 C#中,`Control....
在UI线程中保存`SynchronizationContext`,然后在其他线程中使用它来发送消息回UI线程。 ```csharp SynchronizationContext context = SynchronizationContext.Current; // 在其他线程中 context.Send(_ => ...
4. **Dispatcher或SynchronizationContext**:在WPF或.NET Framework中,可以使用Dispatcher或SynchronizationContext来在UI线程上安全地更新UI元素。这确保了所有对UI的修改都在正确的上下文中执行,防止出现线程...
标题“跨线程调用控件的四种方式”涉及到的核心知识点包括线程同步、UI线程和后台线程之间的交互以及.NET Framework提供的几种处理机制。下面将详细解释这四种方法。 1. **Invoke/BeginInvoke** 这是.NET ...
- **事件和事件处理程序**:在多线程环境中,事件常用来在不同线程之间传递信息。例如,`BackgroundWorker`的事件就是一种典型的跨线程通信方式。 - **SynchronizationContext**:这是.NET Framework的一个类,它...
在Windows Forms环境下,UI(用户界面)线程与后台线程之间的交互必须谨慎处理,以确保线程安全和程序的响应性。这个源码可能提供了一个示例,展示了如何在不同的线程之间传递和管理上下文,以及如何正确地更新UI...