C# 多线程.docx
- 文档编号:29929781
- 上传时间:2023-08-03
- 格式:DOCX
- 页数:17
- 大小:47.43KB
C# 多线程.docx
《C# 多线程.docx》由会员分享,可在线阅读,更多相关《C# 多线程.docx(17页珍藏版)》请在冰豆网上搜索。
C#多线程
如何:
对Windows窗体控件进行线程安全调用
VisualStudio2010
其他版本
∙VisualStudio2008
∙.NETFramework3.0
∙VisualStudio2005
此内容为质量更高的人工翻译。
若想同时查看此页面和原始英文页面的内容,请单击“首选项”然后选择“经典视图”作为您的查看首选项。
如果使用多线程来提高Windows窗体应用程序的性能,则必须确保以线程安全方式调用控件。
访问Windows窗体控件本质上不是线程安全的。
如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。
还可能会出现其他与线程相关的Bug,例如争用情况和死锁。
确保以线程安全方式访问控件非常重要。
在未使用Invoke方法的情况下,从不是创建某个控件的线程的其他线程调用该控件是不安全的。
以下非线程安全的调用的示例。
VB
C#
C++
F#
JScript
复制
//Thiseventhandlercreatesathreadthatcallsa
//WindowsFormscontrolinanunsafeway.
privatevoidsetTextUnsafeBtn_Click(
objectsender,
EventArgse)
{
this.demoThread=
newThread(newThreadStart(this.ThreadProcUnsafe));
this.demoThread.Start();
}
//Thismethodisexecutedontheworkerthreadandmakes
//anunsafecallontheTextBoxcontrol.
privatevoidThreadProcUnsafe()
{
this.textBox1.Text="Thistextwassetunsafely.";
}
.NETFramework可帮助您检测以非线程安全方式访问控件这一问题。
在调试器中运行应用程序时,如果一个不是创建某个控件的线程的其他线程调用该控件,则调试器会引发一个InvalidOperationException,并显示以下消息:
“从不是创建控件控件名称的线程访问它。
”
此异常在调试期间和运行时的某些情况下可靠地发生。
在调试以.NETFramework2.0版之前的.NETFramework编写的应用程序时,可能会出现此异常。
我们强烈建议您在发现此问题时进行修复,但您可以通过将CheckForIllegalCrossThreadCalls属性设置为false来禁用它。
这会使控件像在VisualStudio.NET2003和.NETFramework1.1中一样运行。
说明
如果在窗体上使用ActiveX控件,则在调试器中运行时可能会收到跨线程的InvalidOperationException。
发生这种情况时,ActiveX控件不支持多线程处理。
有关使用Windows窗体的ActiveX控件的更多信息,请参见Windows窗体和非托管应用程序。
如果您使用的是VisualStudio,则可以通过禁用VisualStudio承载进程来阻止此异常。
有关更多信息,请参见如何:
禁用宿主进程和如何:
禁用宿主进程和如何:
禁用承载进程。
对Windows窗体控件进行线程安全调用
对Windows窗体控件进行线程安全调用
1.查询控件的InvokeRequired属性。
2.如果InvokeRequired返回true,则使用实际调用控件的委托来调用Invoke。
3.如果InvokeRequired返回false,则直接调用控件。
在下面的代码示例中,将在由后台线程执行的ThreadProcSafe方法中实现线程安全调用。
如果TextBox控件的InvokeRequired返回true,则ThreadProcSafe方法会创建SetTextCallback的一个实例,并将该实例传递给窗体的Invoke方法。
这使得SetText方法被创建TextBox控件的线程调用,而且在此线程上下文中将直接设置Text属性。
VB
C#
C++
F#
JScript
复制
//Thiseventhandlercreatesathreadthatcallsa
//WindowsFormscontrolinathread-safeway.
privatevoidsetTextSafeBtn_Click(
objectsender,
EventArgse)
{
this.demoThread=
newThread(newThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
//Thismethodisexecutedontheworkerthreadandmakes
//athread-safecallontheTextBoxcontrol.
privatevoidThreadProcSafe()
{
this.SetText("Thistextwassetsafely.");
}
VB
C#
C++
F#
JScript
复制
//Thismethoddemonstratesapatternformakingthread-safe
//callsonaWindowsFormscontrol.
//
//Ifthecallingthreadisdifferentfromthethreadthat
//createdtheTextBoxcontrol,thismethodcreatesa
//SetTextCallbackandcallsitselfasynchronouslyusingthe
//Invokemethod.
//
//Ifthecallingthreadisthesameasthethreadthatcreated
//theTextBoxcontrol,theTextpropertyissetdirectly.
privatevoidSetText(stringtext)
{
//InvokeRequiredrequiredcomparesthethreadIDofthe
//callingthreadtothethreadIDofthecreatingthread.
//Ifthesethreadsaredifferent,itreturnstrue.
if(this.textBox1.InvokeRequired)
{
SetTextCallbackd=newSetTextCallback(SetText);
this.Invoke(d,newobject[]{text});
}
else
{
this.textBox1.Text=text;
}
}
使用BackgroundWorker进行线程安全调用
在应用程序中实现多线程的首选方式是使用BackgroundWorker组件。
BackgroundWorker组件使用事件驱动模型实现多线程。
后台线程运行DoWork事件处理程序,而创建控件的线程运行ProgressChanged和RunWorkerCompleted事件处理程序。
可以从ProgressChanged和RunWorkerCompleted事件处理程序调用控件。
使用BackgroundWorker进行线程安全调用
1.创建一个方法,该方法用于执行您希望在后台线程中完成的工作。
不要调用由此方法中的主线程创建的控件。
2.创建一个方法,用于在后台工作完成后报告结果。
可以调用由此方法中的主线程创建的控件。
3.将步骤1中创建的方法绑定到BackgroundWorker的实例的DoWork事件,并将步骤2中创建的方法绑定到同一实例的RunWorkerCompleted事件。
4.若要启动后台线程,请调用BackgroundWorker实例的RunWorkerAsync方法。
在下面的代码示例中,DoWork事件处理程序使用Sleep来模拟需要花费一些时间完成的工作。
它不调用窗体的TextBox控件。
TextBox控件的Text属性在RunWorkerCompleted事件处理程序中直接设置。
VB
C#
C++
F#
JScript
复制
//ThisBackgroundWorkerisusedtodemonstratethe
//preferredwayofperformingasynchronousoperations.
privateBackgroundWorkerbackgroundWorker1;
VB
C#
C++
F#
JScript
复制
//Thiseventhandlerstartstheform's
//BackgroundWorkerbycallingRunWorkerAsync.
//
//TheTextpropertyoftheTextBoxcontrolisset
//whentheBackgroundWorkerraisestheRunWorkerCompleted
//event.
privatevoidsetTextBackgroundWorkerBtn_Click(
objectsender,
EventArgse)
{
this.backgroundWorker1.RunWorkerAsync();
}
//ThiseventhandlersetstheTextpropertyoftheTextBox
//control.Itiscalledonthethreadthatcreatedthe
//TextBoxcontrol,sothecallisthread-safe.
//
//BackgroundWorkeristhepreferredwaytoperformasynchronous
//operations.
privatevoidbackgroundWorker1_RunWorkerCompleted(
objectsender,
RunWorkerCompletedEventArgse)
{
this.textBox1.Text=
"ThistextwassetsafelybyBackgroundWorker.";
}
也可以使用ProgressChanged事件来报告后台任务的进度。
有关包含该事件的示例,请参见BackgroundWorker。
示例
下面的代码示例是一个完整的Windows窗体应用程序,它包含一个带有三个按钮和一个文本框的窗体。
第一个按钮演示不安全的跨线程访问,第二个按钮演示使用Invoke实现的安全访问,而第三个按钮演示使用BackgroundWorker实现的安全访问。
说明
有关如何运行示例的说明,请参见如何:
使用VisualStudio编译和运行完整的Windows窗体代码示例。
此示例需要引用System.Drawing和System.Windows.Forms程序集。
VB
C#
C++
F#
JScript
复制
usingSystem;
usingSystem.ComponentModel;
usingSystem.Threading;
usingSystem.Windows.Forms;
namespaceCrossThreadDemo
{
publicclassForm1:
Form
{
//Thisdelegateenablesasynchronouscallsforsetting
//thetextpropertyonaTextBoxcontrol.
delegatevoidSetTextCallback(stringtext);
//Thisthreadisusedtodemonstrateboththread-safeand
//unsafewaystocallaWindowsFormscontrol.
privateThreaddemoThread=null;
//ThisBackgroundWorkerisusedtodemonstratethe
//preferredwayofperformingasynchronousoperations.
privateBackgroundWorkerbackgroundWorker1;
privateTextBoxtextBox1;
privateButtonsetTextUnsafeBtn;
privateButtonsetTextSafeBtn;
privateButtonsetTextBackgroundWorkerBtn;
privateSystem.ComponentModel.IContainercomponents=null;
publicForm1()
{
InitializeComponent();
}
protectedoverridevoidDispose(booldisposing)
{
if(disposing&&(components!
=null))
{
components.Dispose();
}
base.Dispose(disposing);
}
//Thiseventhandlercreatesathreadthatcallsa
//WindowsFormscontrolinanunsafeway.
privatevoidsetTextUnsafeBtn_Click(
objectsender,
EventArgse)
{
this.demoThread=
newThread(newThreadStart(this.ThreadProcUnsafe));
this.demoThread.Start();
}
//Thismethodisexecutedontheworkerthreadandmakes
//anunsafecallontheTextBoxcontrol.
privatevoidThreadProcUnsafe()
{
this.textBox1.Text="Thistextwassetunsafely.";
}
//Thiseventhandlercreatesathreadthatcallsa
//WindowsFormscontrolinathread-safeway.
privatevoidsetTextSafeBtn_Click(
objectsender,
EventArgse)
{
this.demoThread=
newThread(newThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
//Thismethodisexecutedontheworkerthreadandmakes
//athread-safecallontheTextBoxcontrol.
privatevoidThreadProcSafe()
{
this.SetText("Thistextwassetsafely.");
}
//Thismethoddemonstratesapatternformakingthread-safe
//callsonaWindowsFormscontrol.
//
//Ifthecallingthreadisdifferentfromthethreadthat
//createdtheTextBoxcontrol,thismethodcreatesa
//SetTextCallbackandcallsitselfasynchronouslyusingthe
//Invokemethod.
//
//Ifthecallingthreadisthesameasthethreadthatcreated
//theTextBoxcontrol,theTextpropertyissetdirectly.
privatevoidSetText(stringtext)
{
//InvokeRequiredrequiredcomparesthethreadIDofthe
//callingthreadtothethreadIDofthecreatingthread.
//Ifthesethreadsaredifferent,itreturnstrue.
if(this.textBox1.InvokeRequired)
{
SetTextCallbackd=newSetTextCallback(SetText);
this.Invoke(d,newobject[]{text});
}
else
{
this.textBox1.Text=text;
}
}
//Thiseventhandlerstartstheform's
//BackgroundWorkerbycallingRunWorkerAsync.
//
//TheTextpropertyoftheTextBoxcontrolisset
//whentheBackgroundWorkerraisestheRunWorkerCompleted
//event.
privatevoidsetTextBackgroundWorkerBtn_Click(
objectsender,
EventArgse)
{
this.backgroundWorker1.RunWorkerAsync();
}
//ThiseventhandlersetstheTextpropertyoftheTextBox
//control.Itiscalledonthethreadthatcreatedthe
//TextBoxcontrol,sothecallisthread-safe.
//
//BackgroundWorkeristhepreferredwaytoperformasynchronous
//operations.
privatevoidbackgroundWorker1_RunWorkerCompleted(
objectsender,
RunWorkerCompletedEventArgse)
{
this.textBox1.Text=
"ThistextwassetsafelybyBackgroundWorker.";
}
#regionWindowsFormDesignergeneratedcode
privatevoidInitializeComponent()
{
this.textBox1=newSystem.Windows.Forms.TextBox();
this.setTextUnsafeBtn=newSystem.Windows.Forms.Button();
this.setTextSafeBtn=newSystem.Windows.Forms.Button();
this.setTextBackgroundWorkerBtn=newSystem.Windows.Forms.Button();
this.backgroundWorker1=newSystem.ComponentModel.BackgroundWorker();
this.SuspendLayout();
//
//textBox1
//
this.textBox1.Location=newSystem.Drawing.Point(12,12);
this.textBox1.Name="textBox1";
this.textBox1.Size=newSystem.Drawing.Size(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 多线程