`
heiyan
  • 浏览: 46212 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

C# Delegate(委托)与多线程

 
阅读更多

很多时候写windows程序都需要结合多线程,在.net中用如下得代码来创建并启动一个新的线程。
public void ThreadProc();
Thread thread = new Thread(new ThreadStart(ThreadProc));
thread.IsBackground = true;
thread.Start();
但是很多时候,在新的线程中,我们需要与UI进行交互,在.net中不允许我们直接这样做。可以参考MSDN中的描述:
“Windows 窗体”使用单线程单元 (STA) 模型,因为“Windows 窗体”基于本机 Win32 窗口,而 Win32 窗口从本质上而言是单元线程。STA 模型意味着可以在任何线程上创建窗口,但窗口一旦创建后就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。除了 Windows 窗体之外,.NET Framework 中的类使用自由线程模型。

STA 模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到(在其上执行)该控件的创建线程。基类 Control 为此目的提供了若干方法(Invoke、BeginInvoke 和 EndInvoke)。Invoke 生成同步方法调用;BeginInvoke 生成异步方法调用。

Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。

正如所看到的,我们必须调用Invoke方法,而BeginInvoke可以认为是Invoke的异步版本。调用方法如下:
public delegate void OutDelegate(string text);
public void OutText(string text)
{
txt.AppendText(text);
txt.AppendText( "/t/n" );
}
OutDelegate outdelegate = new OutDelegate( OutText );
this.BeginInvoke(outdelegate, new object[]{text});

如果我们需要在另外一个线程里面对UI进行操作,我们需要一个类似OutText的函数,还需要一个该函数的委托delegate,当然,这里展 示的是自定义的,.net中还有很多其他类型的委托,可以直接使用,不需要而外声明。例如:MethodInvoker和EventHandler,这两 种类型委托的函数外观是固定的,MethodInvoker是void Function()类型的委托,而EventHandler是void Function(object, EventArgs)类型的委托,第一个不支持参数,第二中的参数类型和数量都是固定的,这两种委托可以很方便的调用,但是缺乏灵活性。请注意 BeginInvoke前面的对象是this,也就是主线程。现在再介绍Control.InvokeRequired,Control是所有控件的基 类,对于这个属性MSDN的描述是:

获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。
也就是说通过判断InvokeRequired可以知道是否需要用委托来调用当前控件的一些方法,如此可以把OutText函数修改一下:

public delegate void OutDelegate(string text);
public void OutText(string text)
{
if( txt.InvokeRequired )
{
OutDelegate outdelegate = new OutDelegate( OutText );
this.BeginInvoke(outdelegate, new object[]{text});
return;
}
txt.AppendText(text);
txt.AppendText( "/t/n" );
}
注意,这里的函数没有返回,如果有返回,需要调用Invoke或者EndInvoke来获得返回的结果,不要因为包装而丢失了返回值。如果调用没有完成,Invoke和EndInvoke都将会引起阻塞。
现在如果我有一个线程函数如下:
public void ThreadProc()
{
for(int i = 0; i < 5; i++)
{
OutText( i.ToString() );
Thread.Sleep(1000);
}
}
如果循环的次数很大,或者漏了Thread.Sleep(1000);,那么你的UI肯定会停止响应,想知道原因吗?看看BeginInvoke前面的对象,没错,就是this,也就是主线程,当你的主线程不停的调用OutText的时候,UI当然会停止响应。
与以前VC中创建一个新的线程需要调用AfxBeginThread函数,该函数中第一个参数就是线程函数的地址,而第二个参数是一个类型为 LPVOID的指针类型,这个参数将传递给线程函数。现在我们没有办法再使用这种方法来传递参数了。我们需要将传递给线程的参数和线程函数包装成一个单独 的类,然后在这个类的构造函数中初始化该线程所需的参数,然后再将该实例的线程函数传递给Thread类的构造函数。代码大致如下:

public class ProcClass
{
private string procParameter = "";
public ProcClass(string parameter)
{
procParameter = parameter;
}
public void ThreadProc()
{
}
}
ProcClass threadProc = new ProcClass("use thread class");
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
就是这样,需要建立一个中间类来传递线程所需的参数。
那么如果我的线程又需要参数,又需要和UI进行交互的时候该怎么办呢?可以修改一下代码:
public class ProcClass
{
private string procParameter = "";
private Form1.OutDelegate delg = null;
public ProcClass(string parameter, Form1.OutDelegate delg)
{
procParameter = parameter;
this.delg = delg;
}
public void ThreadProc()
{
delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);
}
}
ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
//-----------------------以下为自己写的异步委托的例子------------------------
namespace PhsControlDelegate
{
public partial class Form2 : Form
{
PhsControl.phsControl phsObj = new PhsControl.phsControl();
public delegate void OperationDelegate(string strMessage);

public Form2()
{
phsObj.OnJieShouDuanXin +=new PhsControl.JieShouDXHandler(phsObj_OnJieShouDuanXin);
}

public void SetText(string strMessage)
{
txtReceive.AppendText(strMessage);
}

protected void phsObj_OnJieShouDuanXin(Object sender, PhsControl.jsSmsArgs e)
{
OperationDelegate optionDelgate = new OperationDelegate(SetText);

this.BeginInvoke(optionDelgate, new object[] { e.dhHaoMa + " " + e.dxNeiRong + "/t/n" });
}
}
}

分享到:
评论

相关推荐

    VB.Net-C#多线程Thread-代理委托delegate编程

    最近收集的VB.Net-C#多线程Thread-代理委托delegate编程。文章列表: c#.net多线程同步.txt C#WebBrowser页面与WinForm交互技巧一.txt C#多线程编程-多细全.txt C#多线程编程简单实例.txt C#多线程窗体控件安全访问....

    c#多线程利用委托更新控件内容

    该文档给出了在不同线程间实时更新控件textbox数据的代码,利用了委托(delegate)

    C# 通过委托和线程实现chart控件的实时更新

    该文档给出了c#线程实时更新图表及其他控件数据的完成代码,通过委托delegate和控件的BeginInvoke方法实现数据的绑定

    C#多线程委托

    一个简单的C#多线程和委托更新UI的demo

    多线程,Delegate 委托带参数的方法

    Delegate '委托,带参数的方法,多线程,可以轻松在线程中传递参数,获取返回值.

    C#多线程实现定时器

    C#多线程实现定时器 C#多线程实现定时器是指使用C#语言中的多线程编程技术来实现定时器功能。定时器是指在一定的时间间隔内执行某个操作或函数的机制。在C#中,可以使用System.Windows.Forms.Timer控件来实现定时器...

    C#基于委托实现多线程之间操作的方法

    本文实例讲述了C#基于委托实现多线程之间操作的方法。分享给大家供大家参考,具体如下: 有的时候我们要起多个线程,更多的时候可能会有某个线程会去操作其他线程里的属性。 但是线程是并发的,一般的调用是无法实现...

    C#跨窗体(Winform)调用控件(委托回调)

    委托回调

    C#线程间通信

    对于主线程的控件操作采用的是delegate委托的方式,避免主线程假死。 第二:采用的是SendMessage和FindWindow的方式来进行和主线程通信。 第三:改写了DefWndProc,使其支持自主事件。 第四:解决FindWindow 查找不...

    c#多线程进度条参考资料WEb

    多线程 进度条解决方案。 文本,非项目 .定义 委托 delegate void myDelegate(int i); myDelegate mydelegate = null; 2.定义方法,显示消息 public void ShowMessage(int i) { this.textBox1.Text = i....

    C#多线程函数如何传参数和返回值[归类].pdf

    "C#多线程函数如何传参数和返回值" 在C#中,多线程函数的参数传递和返回值处理是非常重要的。多线程函数可以使用委托(delegates)来实现参数的传递和返回值的处理。 委托是具有同样参数和返回值的函数的集合。...

    Delegate与Action.docx

    C#委托与多线程

    C#基于异步事件回调多线程容器

    委托采用Func来定义的,没有采用传统且不太好理解的Delegate。这让代码减少很多,也更容易理解。多线程应该采用消息中心来交换数据,这样就规避了线程同步交互,等待,阻塞等等,全部是异步调用,全部是接收消息工作...

    C#多线程操作控件threading的使用

    C#多线程操作控件threading的使用 在C#中,多线程操作控件是一个常见的问题。由于控件是主线程创建的,因此不能直接从另一个线程访问。这篇文章将探讨如何使用threading来实现多线程操作控件。 首先, let's 看一...

    C#多线程不阻塞[参照].pdf

    C#多线程不阻塞 在这篇文章中,我们将探讨C#中的多线程不阻塞编程。我们将讨论异步方法调用、委托、线程池和异步编程的优点。 同步方法调用 首先,我们来看一下同步方法调用。假设我们有一个函数Foo(),需要执行...

    c#进行项目设计时可以直接使用资源

    3.c#基础委托delegate 4.c#基础多线程 5.c#基础修饰符访问返回值 6.c#基础重载 7.c#基础递归 8.c#基础数组 9.c#基础引用 10.c#基础引用 - 作业 11.c#基础ref和out 12.c#基础二分查找法 13.c#基础数组选择排序 14.c#...

    C# 多线程之基于委托的异步编程

    赤道上的小熊又来了,在开发过程中,如果有一个方法比较耗时,又想获得该方法执行完后的结果,可以使用一个超级简单的方式,那就是基于委托的异步编程,异步方式理论上属于多线程,在执行时每个方法都会重新开启一个...

    跨类跨线程访问C#源代码

    委托(Delegate):委托是一种类型,它代表一个方法,可以用来将方法作为参数传递给其他方法。 Invoke和BeginInvoke方法:在Windows Forms中,每个控件都有一个Invoke方法和一个BeginInvoke方法。 BackgroundWorker...

    ARP扫描局域网主机ip和MAC(c#)归类.pdf

    3. C#多线程编程:C#语言支持多线程编程,通过使用System.Threading命名空间可以创建多个线程来执行不同的任务,从而提高程序的运行速度和稳定性。 4. 委托(Delegate):委托是一种类型安全的回调机制,允许将方法...

    深入理解C#中常见的委托

    今天我要说的是C#中的三种委托方式:Func委托,Action委托,Predicate委托以及这三种委托的常见使用场景。Func,Action,Predicate全面解析首先来说明Func委托,通过MSDN我们可以了解到,Func委托有如下的5种类型: ...

Global site tag (gtag.js) - Google Analytics