位置:首页 > 高级语言 > C#在线教程 > C#多线程

C#多线程

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

线程是轻量级进程。使用线程中的一个常见的例子是由现代操作系统执行并发编程的。使用线程CPU节省周期和应用的增加效率。

到目前为止,我们已经编写的程序在一个单一的线程运行作为一个单一的过程,是应用程序的运行实例。然而,这种方式的应用程序可以在一个时间执行一个作业。使它在一个时间执行多个任务时,它可以被分成更小的线程。

线程生命周期

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

以下是在一个线程的生命周期中的各种状态:

  • 未启动状态: 它是这种情况,创建的线程的实例,但在开始方法尚未被调用时。

  • 就绪状态: 它的情况是当线程准备运行,等待CPU周期。

  • 不可运行状态:线程没有运行的时候:

    • 睡眠方法被调用

    • 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类中最常用的属性:

属性 描述
CurrentContext 获取在该线程正在执行的当前上下文
CurrentCulture 获取或设置当前线程的culture
CurrentPrinciple 获取或设置线程的当前主体(基于角色的安全性)
CurrentThread 获取当前正在运行的线程
CurrentUICulture 获取或设置使用资源管理器来查找区域性特定资源在运行时的当前culture
ExecutionContext 获取包含有关当前线程的各种上下文信息的ExecutionContext对象
IsAlive 获取一个指示当前线程的执行状态
IsBackground 获取或设置一个值,指示线程是否是后台线程
IsThreadPoolThread 获取一个值,指示线程是否不属于管理线程池
ManagedThreadId 获取当前托管线程的唯一标识符
Name 获取或设置线程的名称
Priority 获取或设置一个值,指示线程的调度优先级
ThreadState 获取包含当前线程的状态的值

下表显示了一些Thread类中最常用的方法:

S.N 方法名称和说明
1 public void Abort()
提高在其上调用它的线程一个ThreadAbortException,以开始终止线程的过程。调用此方法通常会终止线程
2 public static LocalDataStoreSlot AllocateDataSlot()
分配所有线程一未命名的数据插槽。为了获得更好的性能,即标有ThreadStaticAttribute使用字段属性来代替
3 public static LocalDataStoreSlot AllocateNamedDataSlot( string name) 
分配上的所有线程命名的数据槽。为了获得更好的性能,即标有ThreadStaticAttribute使用字段属性来代替
4 public static void BeginCriticalRegion()
通知主机的执行是即将进入代码区域,其中一个线程的影响中止未处理的异常的区域可能会危及应用程序域中的其他任务
5 public static void BeginThreadAffinity()
通知的主机托管代码将要执行依赖于当前物理操作系统线程的身份的指示
6 public static void EndCriticalRegion()
通知的主机执行即将进入的或代码,其中一个线程的效果中止未处理的异常的区域被限制在当前的任务
7 public static void EndThreadAffinity()
通知的主机托管代码已完成执行依赖于当前的物理操作系统线程的身份的指示
8 public static void FreeNamedDataSlot(string name)
消除了名称和插槽之间的关联,对于在这个过程中的所有线程。为了获得更好的性能,即标有ThreadStaticAttribute使用字段属性来代替
9 public static Object GetData( LocalDataStoreSlot slot ) 
检索从当前线程上指定槽位的值,在当前线程的当前域内。为了获得更好的性能,即标有ThreadStaticAttribute使用字段属性来代替
10 public static AppDomain GetDomain()
返回在当前线程运行的当前域
11 public static AppDomain GetDomain()
返回一个唯一的应用程序域标识符
12 public static LocalDataStoreSlot GetNamedDataSlot( string name ) 
查找一个命名的数据槽。为了获得更好的性能,即标有ThreadStaticAttribute使用字段属性来代替
13 public void Interrupt()
中断线程WaitSleepJoin线程状态
14 public void Join()
阻塞调用线程,直到某个线程终止,同时继续执行标准的COM和SendMessage消息处理。这种方法有不同的重载形式
15 public static void MemoryBarrier()
同步存储器存取如下:该内存之前调用MemoryBarrier访问该处理器执行当前线程不能重新排序以这样的方式执行的指令之后的存储器访问随后的调用MemoryBarrier
16 public static void ResetAbort()
取消中止请求当前线程
17 public static void SetData( LocalDataStoreSlot slot, Object data ) 
设置数据中当前运行的线程上指定槽位,在线程的当前域。为了获得更好的性能,ThreadStaticAttribute使用字段属性来代替
18 public void Start()
开始一个线程
19 public static void Sleep( int millisecondsTimeout ) 
使线程暂停一段时间
20 public static void SpinWait( int iterations ) 
导致一个线程等待由迭代参数定义的次数
21 public static byte VolatileRead( ref byte address )
public static double VolatileRead( ref double address )
public static int VolatileRead( ref int address )
public static Object VolatileRead( ref Object address ) 

读取一个字段的值。的值是最新的写入通过在计算机的任何处理器,而不管处理器数或处理器高速缓冲存储器的状态的。这种方法有不同的重载形式。只有一些在上文给出
22 public static void VolatileWrite( ref byte address, byte value )
public static void VolatileWrite( ref double address, double value )
public static void VolatileWrite( ref int address, int value )
public static void VolatileWrite( ref Object address, Object value ) 

写入一个值,以立即的字段,使得值是可见的计算机中的所有处理器。这种方法有不同的重载形式。只有一些在上文给出
23 public static bool Yield()
导致调用线程产生执行到另一个线程准备在当前处理器上运行。操作系统的选择产生的线程

创建线程

线程是通过继承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)
        {
            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

管理线程

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

下面的例子说明了如何使用sleep()方法的用于制造线程暂停一段特定的时间。

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
            // the thread is paused for 5000 milliseconds
            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()方法用于销毁线程。

运行时抛出一个ThreadAbortException中止线程。该异常不能被捕获,控制发送到finally块(如果有)。

下面的程序说明了这一点:

using System;
using System.Threading;

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

                Console.WriteLine("Child thread starts");
                // do some work, like counting to 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();
            //stop the main thread for some time
            Thread.Sleep(2000);
            //now abort the child
            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