C# 第八章『多线程』◆第3节:线程的方法

        一、启动线程

        通过提供一个委托来启动线程,该委托表示线程在其类构造函数中执行的方法。 然后调用 Start 方法以开始执行。

        构造函数可以使用两种委托类型之一,具体取决于是否可以将参数 Thread 传递给要执行的方法:

         如果方法没有参数,则向 ThreadStart 构造函数传递委托。 它具有签名:

public delegate void ThreadStart()  

        如果方法具有参数,则向 ParameterizedThreadStart 构造函数传递委托。 它具有签名: 

public delegate void ParameterizedThreadStart(object obj)  

        在C#中创建线程时,首先需要创建一个Thread委托实例,再以这个TreadStart委托作为参数,来构造Thread实例。

        二、Thread 构造函数

        Thread类拥有四种重载的构造函数:

Thread(ParameterizedThreadStart) 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。
Thread(ThreadStart) 初始化 Thread 类的新实例。
Thread(ParameterizedThreadStart, Int32) 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小。
Thread(ThreadStart, Int32) 初始化 Thread 类的新实例,指定线程的最大堆栈大小。

        注意:线程不会在创建时开始执行。 若要计划线程的执行,请调用 Start 方法。 若要将数据对象传递给线程,请使用 Start(Object) 方法重载。

        备注:如果线程已经终止,则无法通过再次调用Start方法来重启线程。

        1、Thread(ParameterizedThreadStart)

初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。
//未使用命名空间
public Thread (System.Threading.ParameterizedThreadStart start);

//使用了命名空间
using System.Threading;
public Thread (ParameterizedThreadStart start);
using System;
using System.Threading;

public class Work
{
    public static void Main()
    {
        // 启动一个调用参数化静态方法的线程。 
        Thread newThread = new Thread(Work.DoWork);
        newThread.Start(42);

        // 启动一个调用参数化实例方法的线程。 
        Work w = new Work();
        newThread = new Thread(w.DoMoreWork);
        newThread.Start("The answer.");
    }

    public static void DoWork(object data)
    {
        Console.WriteLine("Static thread procedure. Data='{0}'",data);
    }

    public void DoMoreWork(object data)
    {
        Console.WriteLine("Instance thread procedure. Data='{0}'",data);
    }
}

        2、Thread(ThreadStart)

//未使用命名空间
public Thread (System.Threading.ThreadStart start);

//使用了命名空间
using System.Threading;
public Thread (ThreadStart start);

        创建执行静态方法的线程:

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        Thread Nt1 =new Thread(new ThreadStart(Work.DoWork));
        Nt1.Start();
    }
}

class Work
{
    public static void DoWork()
    {
        Console.WriteLine("新的线程启动(静态方法)");
    }
}

         创建执行实例方法的线程:

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        Work Nw1 = new Work();
        Thread Nt1 =new Thread(new ThreadStart(Nw1.DoWork));
        Nt1.Start();
    }
}

class Work
{
    public void DoWork()
    {
        Console.WriteLine("新的线程启动(实例方法)");
    }
}

        找错误案例:

         正确修改为:

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        Test x1 = new Test();
        Thread x2 = new Thread(new ThreadStart(x1.DoWork));
        x2.Start();
    }

    public void DoWork()
    {
        Console.WriteLine("新的线程启动(实例方法)");
    }
}

        3、Thread(ParameterizedThreadStart, Int32)

        4、Thread(ThreadStart, Int32)

        三、线程休眠—Thread.Sleep 方法:将当前线程挂起指定的时间。

        线程的休眠是通过Thread类的Sleep方法实现的,而Thread类的实例的IsAlive属性可以判断线程是否执行完毕。

        Sleep方法有两种重载方式:

Sleep(Int32) 将当前线程挂起指定的毫秒数。
Sleep(TimeSpan) 将当前线程挂起指定的时间。

        注意:不要在主线程使用!

        1、Sleep(Int32):将当前线程挂起指定毫秒数,C#语法格式如下:

public static void Sleep (int millisecondsTimeout);

        millisecondsTimeout:Int32,挂起线程的毫秒数。 如果 millisecondsTimeout 参数的值为零,则该线程会将其时间片的剩余部分让给任何已经准备好运行的、具有同等优先级的线程。 如果没有其他已经准备好运行的、具有同等优先级的线程,则不会挂起当前线程的执行。

using System;
using System.Threading;

class Example
{
    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("休眠 2 秒.");
            Thread.Sleep(2000);
        }

        Console.WriteLine("Main thread exits.");
    }
}

        2、Sleep(TimeSpan):将当前线程挂起指定的时间,语法格式如下:

public static void Sleep (TimeSpan timeout);

        timeout:挂起线程的时间量。 如果 timeout 参数的值为零,则该线程会将其时间片的剩余部分让给任何已经准备好运行的、具有同等优先级的线程。 如果没有其他已经准备好运行的、具有同等优先级的线程,则不会挂起当前线程的执行。

将当前线程挂起指定的时间:多少小时,多少分钟,多少秒
public TimeSpan(int hours, int minutes, int seconds);
using System;
using System.Threading;

class Example
{
    static void Main()
    {
        TimeSpan interval = new TimeSpan(0, 0, 2);//0小时0分钟2秒

        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("Sleep for 2 seconds.");
            Thread.Sleep(interval);
        }

        Console.WriteLine("Main thread exits.");
    }
}

        四、终止线程—Abort方法

        当一个线程执行时间太长时,用户有可能要终止这个线程,这个就要使用Abort方法。该方法有两种重载方式:

Abort() 在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
Abort(Object) 引发在其上调用的线程中的 ThreadAbortException 以开始处理终止线程,同时提供有关线程终止的异常信息。 调用此方法通常会终止线程。

        备注:线程的Abort方法用于永久地停止托管线程。在调用Abort方法时,公共语言运行库在目标线程中引发ThreadAbortException异常,目标线程可捕捉此异常。一旦线程终止,将无法重新启动。

在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
public void Abort ();


引发在其上调用的线程中的 ThreadAbortException 以开始处理终止线程,同时提供有关线程终止的异常信息。 调用此方法通常会终止线程。
public void Abort(Object stateInfo)
stateInfo:一个对象,它包含应用程序特定的信息(如状态),该信息可供正被中止的线程使用。
using System;
using System.Threading;

class Test
{
    public static void Main()
    {
        Thread newThread = new Thread(new ThreadStart(TestMethod));
        newThread.Start();
        Thread.Sleep(1000);

        // Abort newThread.
        Console.WriteLine("Main aborting new thread.");
        newThread.Abort("Information from Main.");

        // Wait for the thread to terminate.
        newThread.Join();
        Console.WriteLine("New thread terminated - Main exiting.");
    }

    static void TestMethod()
    {
        try
        {
            while (true)
            {
                Console.WriteLine("New thread running.");
                Thread.Sleep(1000);
            }
        }
        catch (ThreadAbortException abortException)
        {
            Console.WriteLine((string)abortException.ExceptionState);
        }
    }
}

        五、线程的加入 —Join方法:在此实例表示的线程终止前,阻止调用线程。

        Join方法用来阻塞调用线程,直到某个线程终止为止。该方法有三种重载形式:

Join() 在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到由该实例表示的线程终止。
Join(Int32) 在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到由该实例表示的线程终止或经过了指定时间为止。
Join(TimeSpan) 在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到由该实例表示的线程终止或经过了指定时间为止。

         备注:如果在程序中使用了多线程,辅助线程还没有执行完毕,那么在关闭窗体时,必须要关闭辅助线程,否则会引发异常。

        ① Join()

在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到由该实例表示的线程终止。

public void Join ();

Join 是一种同步方法,它阻止调用 (线程,即调用方法的线程) 调用方法的线程 Join 完成。
使用此方法可确保线程已终止。
如果线程未终止,调用方将无限期阻止。 
在下面的示例中,线程调用 的 方法 Thread1 Join() Thread2 ,这会导致 Thread1 在 Thread2 完成后阻止。
using System;
using System.Threading;

public class Example
{
   static Thread thread1, thread2;
   
   public static void Main()
   {
      thread1 = new Thread(ThreadProc);
      thread1.Name = "Thread1";
      thread1.Start();
      
      thread2 = new Thread(ThreadProc);
      thread2.Name = "Thread2";
      thread2.Start();   
   }

   private static void ThreadProc()
   {
      Console.WriteLine("\nCurrent thread: {0}", Thread.CurrentThread.Name);
      if (Thread.CurrentThread.Name == "Thread1" && 
          thread2.ThreadState != ThreadState.Unstarted)
         thread2.Join();
      
      Thread.Sleep(4000);
      Console.WriteLine("\nCurrent thread: {0}", Thread.CurrentThread.Name);
      Console.WriteLine("Thread1: {0}", thread1.ThreadState);
      Console.WriteLine("Thread2: {0}\n", thread2.ThreadState);
   }
}

        时线程已终止 Join ,则该方法将立即返回 。

        ②Join(Int32)

在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到由该实例表示的线程终止或经过了指定时间为止。

public bool Join (int millisecondsTimeout);

参数:millisecondsTimeout—等待线程终止的毫秒数。
如果线程已终止,则为 true;如果 false 参数指定的时间量已过之后还未终止线程,则为 millisecondsTimeout。
using System;
using System.Threading;

public class Example
{
   static Thread thread1, thread2;
   
   public static void Main()
   {
      thread1 = new Thread(ThreadProc);
      thread1.Name = "Thread1";
      thread1.Start();
      
      thread2 = new Thread(ThreadProc);
      thread2.Name = "Thread2";
      thread2.Start();   
   }

   private static void ThreadProc()
   {
      Console.WriteLine("\nCurrent thread: {0}", Thread.CurrentThread.Name);
      if (Thread.CurrentThread.Name == "Thread1" && 
          thread2.ThreadState != ThreadState.Unstarted)
         if (thread2.Join(2000))
            Console.WriteLine("Thread2 has termminated.");
         else
            Console.WriteLine("The timeout has elapsed and Thread1 will resume.");   
      
      Thread.Sleep(4000);
      Console.WriteLine("\nCurrent thread: {0}", Thread.CurrentThread.Name);
      Console.WriteLine("Thread1: {0}", thread1.ThreadState);
      Console.WriteLine("Thread2: {0}\n", thread2.ThreadState);
   }
}

        ③Join(TimeSpan)

在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻止调用线程,直到由该实例表示的线程终止或经过了指定时间为止。

public bool Join (TimeSpan timeout);

timeout:设置等待线程终止的时间量的TimeSpan。
如果线程已终止,则为 true;如果 false 参数指定的时间量已过之后还未终止线程,则为 timeout。
//下面的代码示例演示如何将 值 TimeSpan 与 方法 Join 一起使用。
using System;
using System.Threading;

class Test
{
    static TimeSpan waitTime = new TimeSpan(0, 0, 1);

    public static void Main() 
    {
        Thread newThread = new Thread(Work);
        newThread.Start();

        if(newThread.Join(waitTime + waitTime)) {
            Console.WriteLine("New thread terminated.");
        }
        else {
            Console.WriteLine("Join timed out.");
        }
    }

    static void Work()
    {
        Thread.Sleep(waitTime);
    }
}

         备注:Join(TimeSpan) 是一种同步方法,它阻止调用线程 (,即调用方法) 直到调用方法的线程已完成或已过时间间隔 Join 。

//下面的示例中,线程调用 的 方法,这会导致 阻塞,直到已完成或 Thread1 Join() Thread2 Thread1 Thread2 2 秒已过。
using System;
using System.Threading;

public class Example
{
   static Thread thread1, thread2;
   
   public static void Main()
   {
      thread1 = new Thread(ThreadProc);
      thread1.Name = "Thread1";
      thread1.Start();
      
      thread2 = new Thread(ThreadProc);
      thread2.Name = "Thread2";
      thread2.Start();   
   }

   private static void ThreadProc()
   {
      Console.WriteLine("\nCurrent thread: {0}", Thread.CurrentThread.Name);
      if (Thread.CurrentThread.Name == "Thread1" && 
          thread2.ThreadState != ThreadState.Unstarted)
         if (thread2.Join(TimeSpan.FromSeconds(2)))
            Console.WriteLine("Thread2 has termminated.");
         else
            Console.WriteLine("The timeout has elapsed and Thread1 will resume.");   
      
      Thread.Sleep(4000);
      Console.WriteLine("\nCurrent thread: {0}", Thread.CurrentThread.Name);
      Console.WriteLine("Thread1: {0}", thread1.ThreadState);
      Console.WriteLine("Thread2: {0}\n", thread2.ThreadState);
   }
}

        如果 Timeout.Infinite 为 指定了 ,则此方法的行为与方法重载相同, timeout 返回值 Join() 除外。

        如果调用 时线程已终止 Join ,则该方法将立即返回 。

        此方法更改当前线程的状态以包括 WaitSleepJoin 。 不能对 Join 状态为 的线程 ThreadState.Unstarted 调用 。

        六、线程的挂起与恢复(新版本已弃用)

        Suspend方法用于挂起线程,Resume方法用于继续执行已经挂起的线程。可以使用这两个方法进行线程的同步,和Start方法有些类似的是:在调用Suspend方法后不会立即停止,而是执行到一个安全点后挂起。

        1、Suspend方法

        挂起线程,或者如果线程已挂起,则不起作用。语法格式为:

public void Suspend();

        2、Resume方法

        继续已挂起的线程。语法格式为:

public void Resumne();

猜你喜欢

转载自blog.csdn.net/qq_45336030/article/details/126483194