System.Threading

线程:定义为可执行应用程序中的基本执行单元。

应用程序域:一个应用程序内可能有多个线程。

上下文:一个线程可以移动到一个特定的上下文的实体

导入命名空间:

          //得到正在执行这个方法的线程
            Thread currThread = Thread.CurrentThread;

            //获取正在承载当前线程的应用程序
            AppDomain ad = Thread.GetDomain();

            //获取当前操作线程所处的上下文
            System.Runtime.Remoting.Contexts.Context ct = Thread.CurrentContext;

线程同步的作用:

同一时间,多个线程都能运行共享的功能块。为了保护资源不被破坏,使用各种原语(比如lock,monitor和[Synchronization]特性或语言关键字支持)来控制线程对它们的访问。

使用System.Threading命名空间中定义的类型,.NET4.0或更高版本的TPL(Task Parallel Library,任务并行库)以及.NET4.5中C#的async和await语言关键字,可以比较放心的操作线程。

想要更好的了解线程的方法,先得知道.NET的委托。

委托

.net委托是一个类型安全的、面向对象的函数指针。当定义了一个.NET委托类型时,作为响应,C#编译器将创建一个派生自System.MulticastDelegate的密封类(派生于System.Delegate)  (关于委托的更多介绍以后会写到)

 public delegate int BinaryOp(int x,int y);     //委托跟类同级
    //它能指向任何一个拥有两个整数参数、返回一个整数的方法

例如:

 public delegate int BinaryOp(int x,int y);     //委托跟类同级
    //它能指向任何一个拥有两个整数参数、返回一个整数的方法

    //public sealed class BinaryOp : MulticastDelegate
    //{
    //    public BinaryOp(object target, uint functionAddress);
    //    public int Invoke(int x,int y);
    //    public IAsyncResult BeginInvoke(int x,int y,AsyncCallback cb,object state);
    //    public int EndInvoke(IAsyncResult result);
    //}

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("****请开始你的表演***");
            //输出正在执行中的线程ID
            Console.WriteLine("Main() invoked on thread {0}",Thread.CurrentThread.ManagedThreadId);

            //在同步模式下调用Add()
            BinaryOp b = new BinaryOp(Add);//指向了Add这个方法

            //也能写 b.Invoke(10,10);
            int answer = b(10, 10);
            //直到Add()方法完了后,在会继续执行下面的
            Console.WriteLine("Doing more work in Main()!");
            Console.WriteLine("10+10 is {0}.",answer);
            Console.WriteLine();

        }
        static int Add(int x, int y)
        {
            //输出正在执行中的线程ID
            Console.WriteLine("Add() invoked onthread {0}",Thread.CurrentThread.ManagedThreadId);
            //暂定一下,模拟一个耗时的操作
            Thread.Sleep(5000);
            return x + y;
        }
    }

结果:

因为是同步模式下调用了Add方法,由于程序中所有的任务都是被主线程执行,所有显示的ID是相同的值

BeginInvoke()和EndInvoke()

C#编译器处理delegate关键字的时候,其动态生成的类定义了两个方法BeginInvoke和EndInvoke

   public IAsyncResult BeginInvoke(int x,int y,AsyncCallback cb,object state); //用于异步调用的方法
   public int EndInvoke(IAsyncResult result); //用于获取被调用方法的返回值

先来看看BeginInvoke里面的参数。

传入BeginInvoke()的参数的最初集合必须符合C#委托约定(对于BinaryOp,就是两个整型,后两个参数不知道可以给空)。EndInvoke()唯一参数总是IAsyncResult类型。

System.IAsyncResult 接口

查看定义

 // 摘要:
    //     表示异步操作的状态。
    [ComVisible(true)]
    public interface IAsyncResult
    {
        // 摘要:
        //     获取用户定义的对象,它限定或包含关于异步操作的信息。
        //
        // 返回结果:
        //     用户定义的对象,它限定或包含关于异步操作的信息。
        object AsyncState { get; }
        //
        // 摘要:
        //     获取用于等待异步操作完成的 System.Threading.WaitHandle。
        //
        // 返回结果:
        //     用于等待异步操作完成的 System.Threading.WaitHandle。
        WaitHandle AsyncWaitHandle { get; }
        //
        // 摘要:
        //     获取一个值,该值指示异步操作是否同步完成。
        //
        // 返回结果:
        //     如果异步操作同步完成,则为 true;否则为 false。
        bool CompletedSynchronously { get; }
        //
        // 摘要:
        //     获取一个值,该值指示异步操作是否已完成。
        //
        // 返回结果:
        //     如果操作完成则为 true,否则为 false。
        bool IsCompleted { get; }

BeginInvoke()返回的对象实现了IAsyncResult接口,而EndInvoke()需要一个IAsyncResult兼容类型作为它的参数。

所有如果异步调用一个无返回值的方法就不需要EndInvoke方法了。

异步调用方法:

还是上面的列子,修改一下

        static void Main(string[] args)
        {
            Console.WriteLine("****请开始你的表演***");
            //输出正在执行中的线程ID
            Console.WriteLine("Main() invoked on thread {0}",Thread.CurrentThread.ManagedThreadId);

            //在次线程中调用add
            BinaryOp b = new BinaryOp(Add);//指向了Add这个方法

            IAsyncResult ifAR = b.BeginInvoke(10, 10, null, null);
            Console.WriteLine("Doing more work in Main()!");
            //执行完后获取Add()方法的结果
            int answer = b.EndInvoke(ifAR);
            Console.WriteLine("10+10 is {0}.",answer);
            Console.WriteLine();       

        }

我们看到了两个不同的ID值,这说明在这个应用程序域中有两个线程正在运行。

同步调用线程

我们一运行,Doing more work inMian()  这个语句就会出现,并没有等到5秒。这样的异步调用中主线程可能会被堵塞,那我们的做异步的优势就不明显了,效率似乎不高,我们需要做另一个同步调用:

IAsyncResult提供给了IsCompleted属性。使用这个成员,调用线程在调用EndInvoke()之前,便能判断异步调用是否真正完成。

如果方法没有完成,IsCompleted方法false。

继续改我们的代码:

 static void Main(string[] args)
        {
            Console.WriteLine("****请开始你的表演***");
            //输出正在执行中的线程ID
            Console.WriteLine("Main() invoked on thread {0}",Thread.CurrentThread.ManagedThreadId);

            //在同步模式下调用Add()
            BinaryOp b = new BinaryOp(Add);//指向了Add这个方法

            IAsyncResult ifAR = b.BeginInvoke(10, 10, null, null);               //在Add()方法完成之前会一直显示消息
            while (!ifAR.IsCompleted)
            {
                  Console.WriteLine("Doing more work in Main()!");
                  Thread.Sleep(1000);
            }
           // Console.WriteLine("Doing more work in Main()!");
            //我们指定Add()方法调用完成了
            int answer = b.EndInvoke(ifAR);
            //直到Add()方法完了后,在会继续执行下面的
            Console.WriteLine("10+10 is {0}.",answer);
            Console.WriteLine();

        }

首先我们会执行BeginInvoke方法,会去执行Add()方法,由于需要5秒完成,所以会输出5此doing,我们打断点可以看出先执行Add()在输出doing,直接运行Doing会先出现一遍。

除了IsCompleted属性之外,IAsyncResult接口还提供了AsyncWaiHandle属性以实现更好的灵活的的等待逻辑。返回WaitHandle类型的实例,改实例公开了一个WaitOne()的方法。

此方法可以指定最长等待时间如果超时,返回false.

   while (!ifAR.AsyncWaitHandle.WaitOne(1000,true)) //没有完成异步会一直执行
            {
                Console.WriteLine("Doing more work in Main()!");
            }

这种的形式比上面的好理解些。

AsyncCallback 委托的作用

时间: 2024-10-16 05:03:03

System.Threading的相关文章

vs2013c#测试using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1_CXY { class Program { stati

首先安装Unit Test Generator.方法为:工具->扩展和更新->联机->搜索“图标为装有蓝色液体的小试管.Unit Test Generator”, 编写代码,生成一个新的类,编写构造函数 与 add()函数.代码如下. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Co

System.Threading.ThreadStateException

异常:"System.Threading.ThreadStateException"在未处理的异常类型 System.Windows.Forms.dll 发生 其它信息: 在能够调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 仅仅有将调试器附加到该进程才会引发此异常. 分析:线程间操作产生的异常. 解决方式1:Control.CheckForIllegalCrossThreadCalls =

System.Windows.Forms.Timer、System.Timers.Timer、System.Threading.Timer的差别和分别什么时候用

一.System.Windows.Forms.Timer 1.基于Windows消息循环,用事件方式触发,在界面线程执行:是使用得比较多的Timer,Timer Start之后定时(按设定的Interval)调用挂接在Tick事件上的EvnetHandler.在这种Timer的EventHandler中可 以直接获取和修改UI元素而不会出现问题--因为这种Timer实际上就是在UI线程自身上进行调用的. 2.它是一个基于Form的计时器3.创建之后,你可以使用Interval设置Tick之间的跨

Delphi并行库System.Threading 之ITask 1

不知什么时候,也许是XE8,也许是XE8之前 .Delphi里面多了个System.Threading的并行库. 虽然己经有非常棒的第三方并行库QWorker,但我还是更喜欢官方的东西. 下面是一段使用System.Threading中ITask的代码 procedure TForm3.SpeedButton1Click(Sender: TObject); var tasks: array of ITask; value: Integer; LTask:ITask; X,Y:INTEGER; b

System.Threading.Timer

GLog.WLog("_thdTimer before"); _thdTimer = new System.Threading.Timer(new TimerCallback(TimerProc)); //2秒后开始执行计时器:每3秒执行一次 _thdTimer.Change(2000,3000); GLog.WLog("_thdTimer after"); private void TimerProc(object state) { try { GLog.WLog

C#错误之 System.Threading.ThreadAbortException:正在中止线程

参考:http://www.cnblogs.com/chendaoyin/archive/2013/06/27/3159211.html 1.开启一个子线程 1 //开启一个子线程,子线程调用方法 Method 2 Thread th = new Thread(Method); 3 th.IsBackground = true; 4 th.Start(); 2.线程处理函数 1 public void Method() 2 { 3 try 4 { } 5 catch(Exception ex)

例说定时器System.Threading.Timer

本文通过实例演示System.Threading.Timer的使用方法. 下面是完整的实例代码. using System; using System.Windows; namespace ThreadingTimerExp { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { System.Threading.Timer timer;

using System.Threading;

1 /// <summary> 2 /// 执行动作:耗时而已 3 /// </summary> 4 private void TestThread(string threadName) 5 { 6 Console.WriteLine("TestThread Start Name={2}当前线程的id:{0},当前时间为{1},", 7 System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime

System.Threading.Timer 用法

System.Threading.Timer用法和例子 (1)首先声明Timer变量://一定要声明成局部变量以保持对Timer的引用,否则会被垃圾收集器回收!private System.Threading.Timer timerClose; (2)在上述自动执行代码后面添加如下Timer实例化代码:// Create a timer thread and start ittimerClose = new System.Threading.Timer(new TimerCallback(tim