跳转至

多线程⚓︎

一、多线程概述⚓︎

01 进程与线程⚓︎

进程是一种正在执行的程序。 操作系统使用进程来分隔正在执行的应用程序,而线程是操作系统向其分配处理器时间的基本单元。

每个线程具有计划优先级并维护系统用于保存线程执行暂停时线程上下文的一组结构。 线程上下文包含线程顺畅继续执行所需的全部信息,包括线程的一组 CPU 寄存器和堆栈。 多个线程可在进程上下文中运行。

进程的所有线程共享其虚拟地址空间。 线程可执行任意部分的程序代码,包括其他线程正在执行的部分。

02 何时使用多线程⚓︎

使用多线程可以提高应用程序的响应能力,并利用多处理器或多核系统提高应用程序吞吐量。

请思考桌面应用程序,其主线程负责用户界面元素并响应用户操作。 使用工作线程执行耗时的操作(这些操作会占用主线程并使用户界面无响应)。 此外,可以使用专用线程,提高网络或设备通信对传入消息或事件的响应能力。

如果程序执行可并行执行的操作,可通过在单独线程中执行这些操作并在多处理器或多核系统中运行程序减少总执行时间。 在此类系统中,使用多线程处理可能会提高吞吐量和响应能力。

03 .NET中使用多线程处理⚓︎

从 .NET Framework 4 开始,使用多线程的推荐方法是使用任务并行库(TPL)和并行 LINQ (PLINQ),任务并行库 (TPL) 是 System.Threading 和 System.Threading.Tasks 空间中的一组公共类型和 API。

TPL 和 PLINQ 依赖于 ThreadPool 线程。System.Threading.ThreadPool 类为 .NET 应用程序提供工作线程池。 还可使用线程池线程。 最后,可以使用表示托管线程的 System.Threading.Thread 类。

Warning

请务必处理线程异常,线程中未经处理的异常通常会终止进程。

二、线程生命周期⚓︎

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

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

  • 创建状态:当线程实例被创建但 Start 方法未被调用时的状况。
  • 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
  • 阻塞状态:下面的几种情况下线程是不可运行的:

    • 已经调用 Sleep 方法
    • 已经调用 Wait 方法
    • 通过 I/O 操作阻塞
  • 终止状态:当线程已完成执行或已中止时的状况。

三、创建和使用线程⚓︎

默认情况下,.NET 程序由单个线程(通常称为主线程)启动。 但是,它可以创建其他线程,以与主线程并行或同时执行代码。 这些线程通常称为工作线程。

System.Threading.Thread 提供了线程创建到销毁过程的属性和方法,它允许创建并访问多线程应用程序中的单个线程。

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

01 主线程⚓︎

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();  
        }  
    }  
}
// Output:
// This is MainThread

02 创建与启动线程⚓︎

using System;  
using System.Threading;  

namespace MultithreadingApplication  
{  
    class ThreadCreationProgram  
    {  
        public static void CallToChildThread()  
        {  
            Console.WriteLine("Child thread starts");  
        }  
        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();  
        }  
    }  
}
// Output:
// In Main: Creating the Child thread
// Child thread starts

03 管理线程⚓︎

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();  
        }  
    }  
}

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

04 销毁线程⚓︎

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();  
        }  
    }  
}
// Output:
// 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