`
wyf
  • 浏览: 432952 次
  • 性别: Icon_minigender_1
  • 来自: 唐山
社区版块
存档分类
最新评论

托管线程取消的几种方式

    博客分类:
  • C#
阅读更多

1、以协作方式取消线程

using System;
using System.Threading;

public class ServerClass
{
   public static void StaticMethod(object obj)
   {
      CancellationToken ct = (CancellationToken)obj;
      Console.WriteLine("ServerClass.StaticMethod is running on another thread.");

      // Simulate work that can be canceled.
      while (!ct.IsCancellationRequested) {
         Thread.SpinWait(50000);
      }
      Console.WriteLine("The worker thread has been canceled. Press any key to exit.");
      Console.ReadKey(true);
   }
}

public class Simple
{
   public static void Main()
   {
      // The Simple class controls access to the token source.
      CancellationTokenSource cts = new CancellationTokenSource();

      Console.WriteLine("Press 'C' to terminate the application...\n");
      // Allow the UI thread to capture the token source, so that it
      // can issue the cancel command.
      Thread t1 = new Thread(() => { if (Console.ReadKey(true).KeyChar.ToString().ToUpperInvariant() == "C")
                                     cts.Cancel(); } );

      // ServerClass sees only the token, not the token source.
      Thread t2 = new Thread(new ParameterizedThreadStart(ServerClass.StaticMethod));
      // Start the UI thread.

      t1.Start();

      // Start the worker thread and pass it the token.
      t2.Start(cts.Token);

      t2.Join();
      cts.Dispose();
   }
}
// The example displays the following output:
//       Press 'C' to terminate the application...
//
//       ServerClass.StaticMethod is running on another thread.
//       The worker thread has been canceled. Press any key to exit.

 2、通过轮询侦听取消请求

using System;
using System.Threading;
using System.Threading.Tasks;

public struct Rectangle
{
   public int columns;
   public int rows;
}

class CancelByPolling
{
   static void Main()
   {
      var tokenSource = new CancellationTokenSource();
      // Toy object for demo purposes
      Rectangle rect = new Rectangle() { columns = 1000, rows = 500 };

      // Simple cancellation scenario #1. Calling thread does not wait
      // on the task to complete, and the user delegate simply returns
      // on cancellation request without throwing.
      Task.Run(() => NestedLoops(rect, tokenSource.Token), tokenSource.Token);

      // Simple cancellation scenario #2. Calling thread does not wait
      // on the task to complete, and the user delegate throws
      // OperationCanceledException to shut down task and transition its state.
      // Task.Run(() => PollByTimeSpan(tokenSource.Token), tokenSource.Token);

      Console.WriteLine("Press 'c' to cancel");
      if (Console.ReadKey(true).KeyChar == 'c') {
          tokenSource.Cancel();
          Console.WriteLine("Press any key to exit.");
      }

      Console.ReadKey();
      tokenSource.Dispose();
  }

   static void NestedLoops(Rectangle rect, CancellationToken token)
   {
      for (int x = 0; x < rect.columns && !token.IsCancellationRequested; x++) {
         for (int y = 0; y < rect.rows; y++) {
            // Simulating work.
            Thread.SpinWait(5000);
            Console.Write("{0},{1} ", x, y);
         }

         // Assume that we know that the inner loop is very fast.
         // Therefore, checking once per row is sufficient.
         if (token.IsCancellationRequested) {
            // Cleanup or undo here if necessary...
            Console.WriteLine("\r\nCancelling after row {0}.", x);
            Console.WriteLine("Press any key to exit.");
            // then...
            break;
            // ...or, if using Task:
            // token.ThrowIfCancellationRequested();
         }
      }
   }
}

 3、注册取消请求的回调 token.Register(() => wc.CancelAsync())

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

class CancelWithCallback
{
   static void Main()
   {
      var cts = new CancellationTokenSource();
      var token = cts.Token;
      
      // Start cancelable task.
      Task t = Task.Run( () => {
                    WebClient wc = new WebClient();

                    // Create an event handler to receive the result.
                    wc.DownloadStringCompleted += (obj, e) => {
                               // Check status of WebClient, not external token.
                               if (!e.Cancelled) {
                                  Console.WriteLine("The download has completed:\n");
                                  Console.WriteLine(e.Result + "\n\nPress any key.");
                               }
                               else {
                                  Console.WriteLine("The download was canceled.");
                               }
                    };

                    // Do not initiate download if the external token
                    // has already been canceled.
                    if (!token.IsCancellationRequested) {
                       // Register the callback to a method that can unblock.
                       using (CancellationTokenRegistration ctr = token.Register(() => wc.CancelAsync()))
                       {
                          Console.WriteLine("Starting request\n");
                          wc.DownloadStringAsync(new Uri("http://www.contoso.com"));
                       }
                    }
               }, token);

      Console.WriteLine("Press 'c' to cancel.\n");
      char ch = Console.ReadKey().KeyChar;
      Console.WriteLine();
      if (ch == 'c')
         cts.Cancel();

      Console.WriteLine("Press any key to exit.");
      Console.ReadKey();
      cts.Dispose();
   }
}

 4、侦听具有等待句柄的取消请求

using System;
using System.Threading;
using System.Threading.Tasks;

class CancelOldStyleEvents
{
    // Old-style MRE that doesn't support unified cancellation.
    static ManualResetEvent mre = new ManualResetEvent(false);

    static void Main()
    {
        var cts = new CancellationTokenSource();

        // Pass the same token source to the delegate and to the task instance.
        Task.Run(() => DoWork(cts.Token), cts.Token);
        Console.WriteLine("Press s to start/restart, p to pause, or c to cancel.");
        Console.WriteLine("Or any other key to exit.");

        // Old-style UI thread.
        bool goAgain = true;
        while (goAgain)
        {
            char ch = Console.ReadKey(true).KeyChar;

            switch (ch)
            {
                case 'c':
                    cts.Cancel();
                    break;
                case 'p':
                    mre.Reset();
                    break;
                case 's':
                    mre.Set();
                    break;
                default:
                    goAgain = false;
                    break;
            }

            Thread.Sleep(100);
        }
        cts.Dispose();
    }

    static void DoWork(CancellationToken token)
    {
        while (true)
        {
            // 没有收到信号 将等待
            int eventThatSignaledIndex =
                   WaitHandle.WaitAny(new WaitHandle[] { mre, token.WaitHandle },
                                      new TimeSpan(0, 0, 20));

            // Were we canceled while waiting?
            if (eventThatSignaledIndex == 1)
            {
                Console.WriteLine("The wait operation was canceled.");
                throw new OperationCanceledException(token);
            }
            // Were we canceled while running?
            else if (token.IsCancellationRequested)
            {
                Console.WriteLine("I was canceled while running.");
                token.ThrowIfCancellationRequested();
            }
            // Did we time out?
            else if (eventThatSignaledIndex == WaitHandle.WaitTimeout)
            {
                Console.WriteLine("I timed out.");
                break;
            }
            else
            {
                Console.Write("Working... ");
                // Simulating work.
                Thread.SpinWait(5000000);
            }
        }
    }
}

 5、侦听多个取消请求

此示例展示了如何同时侦听两个取消令牌,以便在其中任意一个令牌发出请求时取消操作。

//创建一个新token 合并内部和外部的tokens

CancellationTokenSource linkedCts =

                CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken)

 

using System;
using System.Threading;
using System.Threading.Tasks;

class LinkedTokenSourceDemo
{
    static void Main()
    {
        WorkerWithTimer worker = new WorkerWithTimer();
        CancellationTokenSource cts = new CancellationTokenSource();

        // Task for UI thread, so we can call Task.Wait wait on the main thread.
        Task.Run(() =>
        {
            Console.WriteLine("Press 'c' to cancel within 3 seconds after work begins.");
            Console.WriteLine("Or let the task time out by doing nothing.");
            if (Console.ReadKey(true).KeyChar == 'c')
                cts.Cancel();
        });

        // Let the user read the UI message.
        Thread.Sleep(1000);

        // Start the worker task.
        Task task = Task.Run(() => worker.DoWork(cts.Token), cts.Token);

        try
        {
            task.Wait(cts.Token);
        }
        catch (OperationCanceledException e)
        {
            if (e.CancellationToken == cts.Token)
                Console.WriteLine("Canceled from UI thread throwing OCE.");
        }
        catch (AggregateException ae)
        {
            Console.WriteLine("AggregateException caught: " + ae.InnerException);
            foreach (var inner in ae.InnerExceptions)
            {
                Console.WriteLine(inner.Message + inner.Source);
            }
        }

        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
        cts.Dispose();
    }
}

class WorkerWithTimer
{
    CancellationTokenSource internalTokenSource = new CancellationTokenSource();
    CancellationToken internalToken;
    CancellationToken externalToken;
    Timer timer;

    public WorkerWithTimer()
    {
        internalTokenSource = new CancellationTokenSource();
        internalToken = internalTokenSource.Token;

        // A toy cancellation trigger that times out after 3 seconds
        // if the user does not press 'c'.
        timer = new Timer(new TimerCallback(CancelAfterTimeout), null, 3000, 3000);
    }

    public void DoWork(CancellationToken externalToken)
    {
        // Create a new token that combines the internal and external tokens.
        //创建一个新token 合并内部和外部的tokens
        this.internalToken = internalTokenSource.Token;
        this.externalToken = externalToken;

        using (CancellationTokenSource linkedCts =
                CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken))
        {
            try
            {
                DoWorkInternal(linkedCts.Token);
            }
            catch (OperationCanceledException)
            {
                if (internalToken.IsCancellationRequested)
                {
                    Console.WriteLine("Operation timed out.");
                }
                else if (externalToken.IsCancellationRequested)
                {
                    Console.WriteLine("Cancelling per user request.");
                    externalToken.ThrowIfCancellationRequested();
                }
            }
        }
    }

    private void DoWorkInternal(CancellationToken token)
    {
        for (int i = 0; i < 1000; i++)
        {
            if (token.IsCancellationRequested)
            {
                // We need to dispose the timer if cancellation
                // was requested by the external token.
                timer.Dispose();

                // Throw the exception.
                token.ThrowIfCancellationRequested();
            }

            // Simulating work.
            Thread.SpinWait(7500000);
            Console.Write("working... ");
        }
    }

    public void CancelAfterTimeout(object state)
    {
        Console.WriteLine("\r\nTimer fired.");
        internalTokenSource.Cancel();
        timer.Dispose();
    }
}

 

 

分享到:
评论

相关推荐

    C# WinForm程序完全退出的问题解决

    ` 这是最为决绝的退出方式,它会立即停止所有线程,包括主线程和其他托管线程,从而彻底结束程序。一般情况下,只有在确保所有必要的清理工作已完成,且不需要等待任何线程完成时才使用此方法。 5. `Application....

    vb.net (c#)中鼠标,键盘钩子Hook

    在Windows API中,主要有以下几种钩子: 1. **WH_MOUSE_LL**:低级鼠标钩子,用于捕获所有线程的鼠标消息。 2. **WH_KEYBOARD_LL**:低级键盘钩子,同样捕获所有线程的键盘消息。 在VB.NET或C#中,我们需要使用P/...

    倒计时关机

    这个程序是用C#编程语言编写的,C#是一种广泛应用于Windows平台开发的面向对象的编程语言,属于.NET框架的一部分。.NET框架为开发者提供了丰富的类库和工具,简化了软件开发过程。 在描述中,作者提到程序“不好”...

    C#007勾月定时关机系统

    5. **多线程**:考虑到定时器可能在后台线程中运行,而关机操作可能需要在主线程上执行,因此需要理解并正确处理多线程环境,以确保程序的正确性。 6. **权限管理**:执行关机操作可能需要管理员权限,因此程序启动...

    定时关机C#

    3. 取消功能:用户应能随时取消已设置的定时关机任务。 4. 服务模式:为了让软件在后台持续运行,开发者可能选择将其设计为Windows服务,即使用户注销或关闭所有应用程序,定时任务仍能继续执行。 总之,【定时关机...

    C#禁止关闭操作系统

    在Windows API中,有几个函数可以用来防止或取消关机,如`SetConsoleCtrlHandler`用于处理控制台事件,`CancelShutdown`用于取消已启动的关机过程。然而,最常用的是`SetWindowLong`和`...

    C#习题.doc

    而属性提供了一种更安全的方式访问字段,通常通过getter和setter方法实现。 #### 二十九、.NET Framework支持封装的方式 - **封装支持**:.NET Framework通过类和接口的定义、访问修饰符如public、private等来支持...

    定时关机小助手(含源码C#版)

    C#是由微软开发的一种面向对象的编程语言,广泛应用于Windows平台的应用程序开发。在这个定时关机小助手中,C#被用来构建用户界面、处理用户输入和执行关机操作。C#支持事件驱动编程,使得用户界面可以响应用户的...

    全程指导Windows下PHP环境配置--不错的自定义PHP环境知道书

    PHP是一种广泛使用的开源脚本语言,尤其适用于Web开发,与HTML、CSS、JavaScript等技术结合,能构建动态、交互性强的网站。本指南将详细介绍如何在Windows系统上搭建PHP运行环境,包括PHP、MySQL和Apache服务器的...

    c#学习笔记.txt

    如前所述,我是一个狮子座男人,一度我认为学习Java会使我看起来与众不同,可是几个月以后我放弃了这个选择,我看了论坛里关于这两种语言孰优孰劣的讨论,最终选择了C#,请不要问我为何做出这样的选择,很多人认为...

    C#编程经验技巧宝典

    14 &lt;br&gt;0028 “///”符号的使用技巧 14 &lt;br&gt;0029 使用注释取消程序语句的执行 15 &lt;br&gt;2.2 语句 15 &lt;br&gt;0030 跳转语句GOTO的使用 15 &lt;br&gt;0031 Continue语句的使用 16 &lt;br&gt;0032 Break...

Global site tag (gtag.js) - Google Analytics