c# 创建、终止线程

来源:互联网 发布:pc发短信软件 编辑:程序博客网 时间:2024/05/14 04:00

该示例创建一个名为Worker 的类,该类包含辅助线程将执行的方法 DoWork。这实际上是辅助线程的 Main 函数。辅助线程将通过调用此方法来开始执行,并在此方法返回时自动终止。DoWork 方法如下所示:

C#
public void DoWork(){    while (!_shouldStop)    {        Console.WriteLine("worker thread: working...");    }    Console.WriteLine("worker thread: terminating gracefully.");}

Worker 类包含另一个方法,该方法用于通知DoWork 它应当返回。此方法名为 RequestStop,如下所示:

C#
复制
public void RequestStop(){    _shouldStop = true;}

RequestStop 方法只是将true 赋给 _shouldStop 数据成员。由于此数据成员由 DoWork 方法来检查,因此这会间接导致DoWork 返回,从而终止辅助线程。但是,需要注意:DoWorkRequestStop 将由不同线程执行。DoWork 由辅助线程执行,而RequestStop 由主线程执行,因此 _shouldStop 数据成员声明为 volatile,如下所示:

C#
复制
private volatile bool _shouldStop;

volatile 关键字用于通知编译器,将有多个线程访问_shouldStop 数据成员,因此它不应当对此成员的状态做任何优化假设。有关更多信息,请参见 volatile(C# 参考)。

通过将volatile_shouldStop 数据成员一起使用,可以从多个线程安全地访问此成员,而不需要使用正式的线程同步技术,但这仅仅是因为_shouldStopbool。这意味着只需要执行单个原子操作就能修改 _shouldStop。但是,如果此数据成员是类、结构或数组,那么,从多个线程访问它可能会导致间歇的数据损坏。假设有一个更改数组中的值的线程。Windows 定期中断线程,以便允许其他线程执行,因此线程会在分配某些数组元素之后和分配其他元素之前被中断。这意味着,数组现在有了一个程序员从不想要的状态,因此,读取此数组的另一个线程可能会失败。

在实际创建辅助线程之前,Main 函数会创建一个Worker 对象和 Thread 的一个实例。线程对象被配置为:通过将对 Worker.DoWork 方法的引用传递给 Thread 构造函数,来将该方法用作入口点,如下所示:

C#
复制
Worker workerObject = new Worker();Thread workerThread = new Thread(workerObject.DoWork);

此时,尽管辅助线程对象已存在并已配置,但尚未创建实际的辅助线程。只有当Main 调用 Start 方法后,才会创建实际的辅助线程:

C#
复制
workerThread.Start();

此时,系统将启动辅助线程的执行,但这是在与主线程异步执行的。这意味着Main 函数将在辅助线程进行初始化的同时继续执行代码。为了保证 Main 函数不会尝试在辅助线程有机会执行之前将它终止,Main 函数将一直循环,直到辅助线程对象的 IsAlive 属性设置为true

C#
复制
while (!workerThread.IsAlive);

下一步,通过调用 Sleep 来将主线程中断片刻。这保证了辅助线程的DoWork 函数在 Main 函数执行其他任何命令之前,在 DoWork 方法内部执行若干次循环:

C#
复制
Thread.Sleep(1);

在 1 毫秒之后,Main 将通知辅助线程对象,它应当使用Worker.RequestStop 方法(前面已介绍)自行终止:

C#
复制
workerObject.RequestStop();

还可以通过调用 Abort 来从一个线程终止另一个线程,但这会强行终止受影响的线程,而不管它是否已完成自己的任务,并且不提供清理资源的机会。此示例中显示的技术是首选方法。

最后,Main 函数对辅助线程对象调用 Join 方法。此方法导致当前线程阻塞或等待,直到对象所表示的线程终止。因此,直到辅助线程返回后,Join 才会返回,然后自行终止:

C#
复制
workerThread.Join();

此时,只有执行Main 的主线程还存在。它会显示一条最终消息,然后返回,从而使主线程也终止。

下面显示了完整的示例:

示例

C#
复制
using System;using System.Threading;public class Worker{    // This method will be called when the thread is started.    public void DoWork()    {        while (!_shouldStop)        {            Console.WriteLine("worker thread: working...");        }        Console.WriteLine("worker thread: terminating gracefully.");    }    public void RequestStop()    {        _shouldStop = true;    }    // Volatile is used as hint to the compiler that this data    // member will be accessed by multiple threads.    private volatile bool _shouldStop;}public class WorkerThreadExample{    static void Main()    {        // Create the thread object. This does not start the thread.        Worker workerObject = new Worker();        Thread workerThread = new Thread(workerObject.DoWork);        // Start the worker thread.        workerThread.Start();        Console.WriteLine("main thread: Starting worker thread...");        // Loop until worker thread activates.        while (!workerThread.IsAlive);        // Put the main thread to sleep for 1 millisecond to        // allow the worker thread to do some work:        Thread.Sleep(1);        // Request that the worker thread stop itself:        workerObject.RequestStop();        // Use the Join method to block the current thread         // until the object's thread terminates.        workerThread.Join();        Console.WriteLine("main thread: Worker thread has terminated.");    }}

示例输出

main thread: starting worker thread...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: working...worker thread: terminating gracefully...main thread: worker thread has terminated
原创粉丝点击