none
关于System.Threading.Tasks.Task的取消 RRS feed

  • 问题

  • 多线程上传FTP,同时上传多个文件,以前用的Thread,  需求中有暂停上传的需求,以前是用的Thread.Abort()

    现在换成了Task,用TaskFactory构建的, 关于暂停,微软提供了一种协作式取消的方式 CancellationTokenSource.

    微软的示例里是在Task的作用域里一个轮询监听外部CancellationTokenSource.Cancel().

    对应我的上传该怎么处理,   上传FTP是另外一个公共类中,有登陆请求,Socket流的写入,这些步骤中不好去检测取消,请问该怎么处理

            private CancellationTokenSource cts = new CancellationTokenSource();
    
            private TaskFactory taskFactory = new TaskFactory();
    
            private void Work()
            {
                taskFactory.StartNew(() => {
    
                    //检测是否取消
                    while (cts.IsCancellationRequested)
                    {
                        cts.Token.ThrowIfCancellationRequested();
                    }
    
                    //上传,写在这个地方根本无法执行
                    //但是现在while里面,又需要在上传的过程中知道是否被取消,这个上传该放在哪里,该怎么处理
                    Upload();
                });
            }
    
            private void Upload()
            {
                LoginFtp();
                WriterStream();
            }
    
            private void Stop()
            {
                cts.Cancel();
            }
    

    谢谢

    2013年3月26日 8:21

答案


  • 我觉应该在把ftp api定义成task, 然后传cancleToken去取消,另外注意cancle操作是延迟的,task不会立即取消任务。

      类似与这样的伪代码

                taskFactory.StartNew(() =>
                {
                    LoginFTP();
                    int bytesSent = ftpStream.Read(byteBuffer, 0, bufferSize); //读流
                    while (bytesRead > 0)
                    {
                        if (cts.IsCancellationRequested)
                        {
                            cts.Token.ThrowIfCancellationRequested();
                            break;
                        }
    
    		localFileStream.Write(byteBuffer, 0, bytesRead); //写流
                    bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize); //继续
                	}
                }, cts.Token);

    ftp代码参考http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class




    2013年3月27日 2:53

全部回复

  • 或许你应该考虑此创建一个事件:

    private CancellationTokenSource cts = new CancellationTokenSource();

    public event Action CancelOnUploading = null; private TaskFactory taskFactory = new TaskFactory(); private void Work() { taskFactory.StartNew(() => { //检测是否取消 while (true) { if(cts.IsCancelRequest)
    {
    cts.ThrowIf......();

     CancelOnUploading(); //引发事件
    break;
    }
    Upload();

    } }); } private void Upload() { LoginFtp(); WriterStream(); } private void Stop() { cts.Cancel(); }

    然后设法在事件中处理你的东西。


    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats


    2013年3月26日 8:37
    版主
  • 也可以尝试使用CancellationToken类的Register方法: http://msdn.microsoft.com/zh-cn/library/vstudio/dd321953.aspx

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats

    2013年3月26日 9:08
    版主
  • 或许你应该考虑此创建一个事件:

    private CancellationTokenSource cts = new CancellationTokenSource();

    public event Action CancelOnUploading = null; private TaskFactory taskFactory = new TaskFactory(); private void Work() { taskFactory.StartNew(() => { //检测是否取消 while (true) { if(cts.IsCancelRequest)
    {
    cts.ThrowIf......();

     CancelOnUploading(); //引发事件
    break;
    }
    Upload();

    } }); } private void Upload() { LoginFtp(); WriterStream(); } private void Stop() { cts.Cancel(); }

    然后设法在事件中处理你的东西。


    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats

    您好, 非常感谢您的回答, 不知道是不是这样?

    但是依然无法停止Upload的操作,例如:

     class Program
        {
            private static TaskFactory taskFactory = new TaskFactory();
            private static CancellationTokenSource cts = new CancellationTokenSource();
            public static event Action CancelOnUploading = null;
    
            static void Main(string[] args)
            {
                Console.WriteLine("Upload Start......");
                taskFactory.StartNew(() => {
                    while (true)
                    {
                        if(cts.IsCancellationRequested)
                        {
                            cts.Token.ThrowIfCancellationRequested();
                            CancelOnUploading = DoCancle;   //引发事件
                            break;
                        }
                        Upload();
                    }
                });
    
                Console.ReadKey();
                cts.Cancel();
                Console.WriteLine("Execute Cancel...");
                Console.ReadKey();
            }
    
            static void DoCancle()
            {
                Console.WriteLine("Task Cancle,Stop Upload...");
            }
    
            private static void Upload()
            {
                Console.WriteLine("DoLogin ...");
                Thread.Sleep(1000);
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("当前Upload Progress {0}%",i+1);
                    Thread.Sleep(1000);
                }
            }
    
        }

    我已经取消了,Upload依然在执行,无法停止Upload的操作.


    2013年3月26日 9:31
  • 换一种做法:
    什么事件也不要,只要在Upload方法里边也判断是否取消了load即可,譬如:
    private void Upload()
            {
               if(!cts.IsCancellationRequired)
               {
                LoginFtp();
                WriterStream();
               }
            }

    Task里边循环判断即可:

    cts.ThrowIfCanllationRequired();
    Upload();

    If you think one reply solves your problem, please mark it as An Answer, if you think someone's reply helps you, please mark it as a Proposed Answer

    Help by clicking:
    Click here to donate your rice to the poor
    Click to Donate
    Click to feed Dogs & Cats

    2013年3月26日 9:48
    版主

  • 我觉应该在把ftp api定义成task, 然后传cancleToken去取消,另外注意cancle操作是延迟的,task不会立即取消任务。

      类似与这样的伪代码

                taskFactory.StartNew(() =>
                {
                    LoginFTP();
                    int bytesSent = ftpStream.Read(byteBuffer, 0, bufferSize); //读流
                    while (bytesRead > 0)
                    {
                        if (cts.IsCancellationRequested)
                        {
                            cts.Token.ThrowIfCancellationRequested();
                            break;
                        }
    
    		localFileStream.Write(byteBuffer, 0, bytesRead); //写流
                    bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize); //继续
                	}
                }, cts.Token);

    ftp代码参考http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class




    2013年3月27日 2:53

  • 我觉应该在把ftp api定义成task, 然后传cancleToken去取消,另外注意cancle操作是延迟的,task不会立即取消任务。

      类似与这样的伪代码

                taskFactory.StartNew(() =>
                {
                    LoginFTP();
                    int bytesSent = ftpStream.Read(byteBuffer, 0, bufferSize); //读流
                    while (bytesRead > 0)
                    {
                        if (cts.IsCancellationRequested)
                        {
                            cts.Token.ThrowIfCancellationRequested();
                            break;
                        }
    
    		localFileStream.Write(byteBuffer, 0, bytesRead); //写流
                    bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize); //继续
                	}
                });

    ftp代码参考http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class



    嗯  您说的有道理,  我现在只能将 cancleToken传递Upload方法中, 或者在Upload函数所在的类中,处理一个对upload进行释放的取消方法,再注册个委托,Token.Register来调用资源释放的函数
    2013年3月27日 3:03
  • 另外你需要调用     
            public Task StartNew(Action action, CancellationToken cancellationToken);

    记得把CancellationToken 传进去,不然还真没法取消任务。

    这样

    void upload(CancellationToken ct)

    {

    ....

    }

    CancellationTokenSource cts = new CancellationTokenSource(); 
    taskFactory.StartNew(() => upload(cts.Token), cts.Token); 


    2013年3月27日 3:20