C#【高级篇】 C# 多线程

C#学习汇总 - 总目录

C#【高级篇】 C# 多线程

前言

线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。

线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率

到目前为止我们编写的程序是一个单线程作为应用程序的运行实例的单一的过程运行的。但是,这样子应用程序同时只能执行一个任务。为了同时执行多个任务,它可以被划分为更小的线程


一、线程生命周期

线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。

下面列出了线程生命周期中的各种状态:

  • 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。

  • 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。

  • 不可运行状态:下面的几种情况下线程是不可运行的:

    已经调用 Sleep 方法
    已经调用 Wait 方法
    通过 I/O 操作阻塞

  • 死亡状态:当线程已完成执行或已中止时的状况。

二、主线程

在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程

当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程

下面的程序演示了主线程的执行:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class MainThreadProgram
    {
        static void Main(string[] args)
        {
            Thread th = Thread.CurrentThread;
            th.Name = "MainThread";
            Console.WriteLine("This is {0}", th.Name);
            Console.ReadKey();
        }
    }
}

运行结果:

This is MainThread

三、创建线程

线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开始子线程的执行。

下面的程序演示了这个概念:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
        }
       
        static void Main(string[] args)
        {
            //【写法1】:ThreadStart、Thread都使用
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
         
         	//【写法2】只使用Thread。在2.0以后可以像下边这样写,程序会更简单易懂点
  				//Thread childThread = new Thread(CallToChildThread);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

运行结果:

In Main: Creating the Child thread
Child thread starts

特别说明:

下边两种写法的效果是一样的。都是创建一个线程。后者只是 C# 的语法,编译时编译器会自动转换成第一种的形式。ThreadStart 是线程的入口,可以理解为一个函数指针,指向线程将要运行的函数。

Thread childThread = new Thread( new ThreadStart(CallToChildThread));

Thread childThread = new Thread(CallToChildThread);

四、管理线程【Thread.Sleep(1000) 线程暂停1s】

Thread 类提供了各种管理线程的方法。

下面的实例演示了 sleep() 方法的使用,用于在一个特定的时间暂停线程。

using System;

using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
            // 线程暂停 5000 毫秒
            int sleepfor = 5000;
            Console.WriteLine("Child Thread Paused for {0} seconds",
                              sleepfor / 1000);
            Thread.Sleep(sleepfor);
            Console.WriteLine("Child thread resumes");
        }
       
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

运行结果:

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes

五、销毁线程【Abort()】

Abort() 方法用于销毁线程。

通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。

下面的程序说明了这点:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            try
            {

                Console.WriteLine("Child thread starts");
                // 计数到 10
                for (int counter = 0; counter <= 10; counter++)
                {
                    Thread.Sleep(500);
                    Console.WriteLine(counter);
                }
                Console.WriteLine("Child Thread Completed");

            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Thread Abort Exception");
            }
            finally
            {
                Console.WriteLine("Couldn't catch the Thread Exception");
            }

        }
       
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            // 停止主线程一段时间
            Thread.Sleep(2000);
            // 现在中止子线程
            Console.WriteLine("In Main: Aborting the Child thread");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception 

总结

  • 进程和线程的理解:进程(一个程序)、线程(并发时多个分支程序)、主线程(Main)
  • 多线程的常见使用:Sleep、Abort、Resume
  • 线程池和Task简单了解

补充1【Thread、线程池ThreadPool、Task】

C# 4.0 以后一共有3种创建线程的方式:

  • ==Thread ==自己创建的独立的线程, 优先级高,需要使用者自己管理。
  • ==ThreadPool ==有 .Net 自己管理, 只需要把需要处理的方法写好, 然后交个.Net Framework, 后续只要方法执行完毕, 则自动退出。
  • Task 4.0 以后新增的线程操作方式, 类似 ThreadPool, 但效率测试比ThreadPool略高, Task对多核的支持更为明显,所以在多核的处理器中, Task的优势更为明显

实例:

using System;
using System.Threading;

namespace ConsoleApp2
{
    class Program
    {
        public static Thread t =null;
        static void Main(string[] args)
        {  
            //【01】独立创建线程
            t = new Thread(ThreadProcess1);
            t.Start(new object());

            //【02】线程池
            ThreadPool.QueueUserWorkItem(ThreadProcess2, new object());
            //【03】Task方式创建线程
            System.Threading.Tasks.Task.Factory.StartNew(ThreadProcess3, new object());

            Console.ReadLine();
        }
        private static void ThreadProcess1(object tag)
        {
            int i = 10;
            while (i > 0)
            {
                Console.WriteLine(string.Format("【01】i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
            Console.WriteLine("【01】线程结束");

            //需要手动终止
            t.Abort();

        }
        private static void ThreadProcess2(object tag)
        {
            int i = 10;
            while (i > 0)
            {
                Console.WriteLine(string.Format("【02】i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
            Console.WriteLine("【02】线程结束");

        }
        private static void ThreadProcess3(object tag)
        {
            int i = 10;
            while (i > 0)
            {
                Console.WriteLine(string.Format("【03】i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
            Console.WriteLine("【03】线程结束");

        }
    }
}

运行结果:
在这里插入图片描述

补充2【ThreadStart和ParameterizedThreadStart】

线程函数通过委托传递,可以不带参数,也可以带参数(只能有一个参数),可以用一个类或结构体封装参数:

using System;
using System.Threading;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(TestMethod));
            Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));
            t1.IsBackground = true;
            t2.IsBackground = true;
            t1.Start();
            t2.Start("hello");
            Console.ReadKey();
        }

        public static void TestMethod()
        {
            Console.WriteLine("不带参数的线程函数");
        }

        public static void TestMethod(object data)
        {
            string datastr = data as string;
            Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
        }
    }
}

运行结果:

不带参数的线程函数
带参数的线程函数,参数为:hello

C#学习汇总 - 总目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值