线程基础和异步执行计算限制

线程基础

进程是一个应用程序实例要使用资源的集合。无法与windows内核的数据和代码沟通,维持系统的健壮性。

线程是一个虚拟的cpu,防止和其他的程序混在一起,最终是操作系统瘫痪掉。

线程的要素:线程内核对象、线程环境块、用户模式栈、内核模式栈、Dll线程链接和线程分离通知。

A、线程内核对象:每个线程初始化时都带有这种数据结构。数据结构包括描述线程的属性和线程上下文(上下文是内存块,主要包含CPU的寄存器集合,寄存器是cpu的组成部分,可以用来暂存指令,数据和地址。)

B、线程环境块:是在用户模式中分配和初始化的内存块(内存是是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据)

C、用户模式栈:主要存储传给方法的变量和实参。还包括一个地址,知道方法执行完从哪里继续。

D、内核模式栈:如果程序需要和操作系统内核打交道的话,需要把用户模式栈中的数据传到内核模式栈,经过验证后,让os进行相关操作。

E、dll线程链接和线程分离通知,一种标志。

时间片的切换让操作系统可以一个程序进入了死循环,然后可以继续执行其他程序,而不需要重启操作系统,但切换影响效率。

clr使用的是windows的线程处理能力。

Console.WriteLine("Main thread: starting a dedicated thread " +
           "to do an asynchronous operation");
        Thread dedicatedThread = new Thread(ComputeBoundOp);
        dedicatedThread.Start(5);

        Console.WriteLine("Main thread: Doing other work here...");
        //Thread.Sleep(10000);     // Simulating other work (10 seconds)

        dedicatedThread.Join();  // 等待dedicatedThread线程执行完才会继续下面的线程
        Console.WriteLine("haiziguo");
        Console.ReadLine();
    }

    // This method's signature must match the ParametizedThreadStart delegate
    private static void ComputeBoundOp(Object state)
    {
        // This method is executed by a thread pool thread

        Console.WriteLine("In ComputeBoundOp: state={0}", state);
        Thread.Sleep(10000);  // Simulates other work (1 second)

        // When this method returns, the dedicated thread dies
    }

所有的前台线程停止,后台线程必须停止,且不会抛出异常。

计算限制异步编程——线程池

CLR包含了代码来管理他自己的线程池。一个CLR包括一个线程池。

默认线程池创建的线程都是后台线程。

线程池将自己的线程划分为工作者线程和IO线程。

IO线程用于通知你的代码一个异步IO限制操作已经完成。

异步编程模式发出IO请求,比如访问文件、网络服务器、数据库、web服务、其他硬件设备。

线程上下文(CallContext)通常是在主线程流向辅助线程,以使主线程和辅助线程的各种权限一致,当然可以阻止流动。

CallContext.LogicalSetData("Name", "Jeffrey");

        // Initiate some work to be done by a thread pool thread
        // The thread pool thread can access the logical call context data 
        ThreadPool.QueueUserWorkItem(
           state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));


        // Suppress the flowing of the Main thread’s execution context
        ExecutionContext.SuppressFlow();

        // Initiate some work to be done by a thread pool thread
        // The thread pool thread can NOT access the logical call context data
        ThreadPool.QueueUserWorkItem(
           state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));

取消线程操作:

private static void CancellingAWorkItem()
    {
        CancellationTokenSource cts = new CancellationTokenSource();

        // Pass the CancellationToken and the number-to-count-to into the operation
        ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));

        Console.WriteLine("Press <Enter> to cancel the operation.");
        Console.ReadLine();
        cts.Cancel();  // If Count returned already, Cancel has no effect on it
        // Cancel returns immediately, and the method continues running here...

        Console.ReadLine();  // For testing purposes
    }

    private static void Count(CancellationToken token, Int32 countTo)
    {
        for (Int32 count = 0; count < countTo; count++)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Count is cancelled");
                break; // Exit the loop to stop the operation
            }

            Console.WriteLine(count);
            Thread.Sleep(200);   // For demo, waste some time
        }
        Console.WriteLine("Count is done");
    }

如果禁止被取消时,可以传入一个Token的静态变量。可以使用CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);来创建多个,一个取消时,LinkedTokenSource就取消。可以创建多个。

计算限制异步编程——任务

线程池的QueueUserWorkItem没有返回值,不知道什么时间结束。下面给出含有返回值的Task代码

Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 10000);

        // You can start the task sometime later
        t.Start();

        // Optionally, you can explicitly wait for the task to complete
        t.Wait(); // FYI: Overloads exist accepting a timeout/CancellationToken


        // Get the result (the Result property internally calls Wait) 
        Console.WriteLine("The sum is: " + t.Result);   // An Int32 value

Task条用Wait的两种情况:a.已经开始Start,调用Task的线程阻塞,直到Task完成为止;b.没有start,调用Task线程不会出现阻塞,而是使用需要等Task完成后才继续线程原来正在执行的操作。可以理解为一个是“线程阻塞”,一个是“步骤阻塞”。

当Task出现异常的话,只有在使用wait和result时才能发现。

下面代码演示如何判断取消Task

private static Int32 Sum(CancellationToken ct, Int32 n)
    {
        Int32 sum = 0;
        for (; n > 0; n--)
        {

            // The following line throws OperationCanceledException when Cancel 
            // is called on the CancellationTokenSource referred to by the token
            //如果使用CancellationToken的取消,那么就抛出异常,
            //判断是否是指定的异常,来判断是否是取消了任务
            ct.ThrowIfCancellationRequested();
          Console.WriteLine(n);
            //Thread.Sleep(0);   // Simulate taking a long time
            checked { sum += n; }
        }
        return sum;
    }
private static void Cancel()
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        Task<Int32> t = new Task<Int32>(() => Sum(cts.Token, 10000), cts.Token);

        t.Start();

        // Sometime later, cancel the CancellationTokenSource to cancel the Task
        cts.Cancel();

        try
        {
            // If the task got canceled, Result will throw an AggregateException
            Console.WriteLine("The sum is: " + t.Result);   // An Int32 value
        }
        catch (AggregateException ae)
        {
            // Consider any OperationCanceledException objects as handled. 
            // Any other exceptions cause a new AggregateException containing 
            // only the unhandled exceptions to be thrown          
            ae.Handle(e => e is OperationCanceledException);

            // If all the exceptions were handled, the following executes
            Console.WriteLine("Sum was canceled");
        }
    }

一个任务完成后继续另外一个任务,继续的任务会自动开始

//继续的任务会自动开始
        // Create Task, defer starting it, continue with another task
        Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 10000);

        // You can start the task sometime later
        t.Start();

        // ContinueWith returns a Task but you usually don't care
        Task cwt = t.ContinueWith(task => Console.WriteLine("The sum is: " + task.Result));
        //cwt.Start();

执行定时计算限制操作

//
        // 摘要:
        //     用 32 位无符号整数来度量时间间隔,以初始化 Timer 类的新实例。
        //
        // 参数:
        //   callback:
        //     一个 System.Threading.TimerCallback 委托,表示要执行的方法。
        //
        //   state:
        //     一个包含回调方法要使用的信息的对象,或者为 null。
        //
        //   dueTime:
        //     调用 callback 之前延迟的时间量(以毫秒为单位)。 指定 System.Threading.Timeout.Infinite 可防止启动计时器。
        //     指定零 (0) 可立即启动计时器。
        //
        //   period:
        //     调用 callback 的时间间隔(以毫秒为单位)。 指定 System.Threading.Timeout.Infinite 可以禁用定期终止。
        //
        // 异常:
        //   System.ArgumentOutOfRangeException:
        //     dueTime 或 period 参数为负,并且不等于 System.Threading.Timeout.Infinite。
        //
        //   System.ArgumentNullException:
        //     callback 参数为 null。
        [CLSCompliant(false)]
        [SecuritySafeCritical]
        public Timer(TimerCallback callback, object state, uint dueTime, uint period);

线程池为所有的Timer对象只使用一个线程。当第一个对象还没有执行完,下一个就开始了,肯定会出现重复执行timer的事件了,为了防止这样事件的放生,可以如下

Timer timer = new Timer((s) =>
        {
            for (int i = 0; i < 1000; i++)
            {
                Console.WriteLine(i);
            }
        }, null, 0,Timeout.Infinite);
        Thread.Sleep(5000);
        timer.Change(0, Timeout.Infinite);

Timeout.Infinite, 然后再使用Change。

原文地址:https://www.cnblogs.com/lzhp/p/3420934.html