使用Task<>的C#不定式任务循环上课+取消

时间:2014-11-19 12:44:51

标签: c# .net multithreading winforms task

我试图为我的WinForm项目中的多线程使用创建一个小类。

Tried Threads(UI问题),Backgroundworker(smth也出错了,现在就离开:)),现在尝试用 Task 类来做。但是现在,不能理解,如何为所有正在运行的任务创建一个不定式循环和一个取消方法(在课堂上)。 我发现的例子是用于1种方法。

所以,这是一个结构&当前工作部分的代码(在WinForm代码中使用的Worker.css和methonds)。

Worker.css

class Worker
{
    public static int threadCount { get; set; }

    public void doWork(ParameterizedThreadStart method)
    {
        Task[] tasks = Enumerable.Range(0, 4).Select(i => Task.Factory.StartNew(() => method(i))).ToArray();
    }
}

用法 的 Form1.cs的

    private void Start_btn_Click(object sender, EventArgs e)
    {
        Worker.threadCount = 1; //actually it doesn`t using now, number of tasks is declared in class temporaly
        Worker worker = new Worker();
        worker.doWork(Job);

        string logString_1 = string.Format("Starting {0} threads...", Worker.threadCount);
        log(logString_1);

    }

    public static int j = 0;
    private void Job(object sender)
    {
        Worker worker = new Worker();
        Random r = new Random();

        log("Thread "+Thread.CurrentThread.ManagedThreadId +" is working...");
        for (int i = 0; i < 5; i++)
        {
            j++;
            log("J==" + j);
            if (j == 50)
            {
                //worker.Stop();
                log("STOP");
            }
        }
        Thread.Sleep(r.Next(500, 1000));
    }

所以,它运行了一个示例4个线程,它们执行了,我的日志中得到J == 20,没关系。

我的问题是,如何为 Worker.doWork()方法创建的任务实现不定循环。 并且还为Worker类创建一个.Stop()方法(它应该在调用时停止所有任务)。据我了解它是相关的问题,所以我把它放在1中。

我尝试了一些解决方案,但所有这些解决方案都基于 CancellationToken 用法,但我必须仅在Worker.doWork()方法内创建此元素,所以我不能使用用于创建Worker.Stop()方法的相同标记。

有人可以帮忙吗?我必须在这个软件中使用的线程数量范围约为5-200个线程。 使用 J 计算只是用于停止软件工作(停止任务/线程)的简单条件的一个示例。 实际上,停止条件主要类似于Queue&lt;&gt;。已完成,或列出&lt;&gt;元素是空的(完成)。

2 个答案:

答案 0 :(得分:0)

最后,让它运作起来。

class Worker
{
    public static int threadCount { get; set; }
    Task[] tasks;

    //ex data
    public static string exception;

    static CancellationTokenSource wtoken = new CancellationTokenSource();
    CancellationToken cancellationToken = wtoken.Token;
    public void doWork(ParameterizedThreadStart method)
    {
        try
        {
            tasks = Enumerable.Range(0, 4).Select(i => Task.Factory.StartNew(() =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    method(i);
                }
            }, cancellationToken)).ToArray();
        }
        catch (Exception ex) { exception = ex.Message; }
    }


    public void HardStop()
    {
        try
        {
            using (wtoken)
            {
              wtoken.Cancel();
            }
            wtoken = null;
            tasks = null;
        }
        catch (Exception ex) { exception = ex.Message; }
    }
}

但如果我使用此方法退出 cancellationToken.ThrowIfCancellationRequested(); 得到一个错误: 当 Job()方法达到J == 50,并且调用了worker.HardStop()函数时,程序窗口崩溃并且我得到并且异常“OparetionCanceledException未被用户代码处理” 在这个字符串上

cancellationToken.ThrowIfCancellationRequested();

所以,什么错了?我已经把它放在try {} catch(){} 据我所知,在wtoken.Cancel();中的任务(Task.IsCancelled == false,Task.IsFaulted == true)中应该更改一些布尔属性。

答案 1 :(得分:0)

我为此避免了所有的任务,并使用了Microsoft的Reactive Framework(NuGet&#34; Rx-Main&#34;)。

以下是:

var r = new Random();

var query =
    Observable
        .Range(0, 4, Scheduler.Default)
        .Select(i =>
            Observable
                .Generate(0, x => true, x => x, x => x,
                    x => TimeSpan.FromMilliseconds(r.Next(500, 1000)),
                    Scheduler.Default)
                .Select(x => i))
        .Merge();

var subscription =
    query
        .Subscribe(i => method(i));

如果您想取消对方法的调用,请执行以下操作:

subscription.Dispose();

我已经对此进行了测试,它就像一种享受。


如果我将它包装在你的worker课程中,那么它看起来像这样:

class Worker
{
    private Random _r = new Random();
    private IDisposable _subscription = null;

    public void doWork()
    {
        _subscription =
            Observable
                .Range(0, 4, Scheduler.Default)
                .Select(n =>
                    Observable
                        .Generate(
                            0, x => true, x => x, x => x,
                            x => TimeSpan.FromMilliseconds(_r.Next(500, 1000)),
                            Scheduler.Default)
                        .Select(x => n))
                .Merge()
                .Subscribe(i => method(i));
    }


    public void HardStop()
    {
        _subscription.Dispose();
    }
}