簡體   English   中英

使用Task <>類+取消的C#不定式任務循環

[英]C# infinitive task loop using Task<> class + cancellation

我正在嘗試為WinForm項目中的多線程用法制作一個小類。

嘗試線程(UI問題),Backgroundworker(UI也出錯),現在就離開:)),現在嘗試使用Task類來完成。 但是現在,我不明白如何為所有正在運行的任務創建一個無限循環和一個取消方法(在類中)。 我發現的示例將在一種方法中使用。

因此,這是當前工作部分的結構和代碼(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 <>已完成,或者List <>元素為空(已完成)。

最后,使它起作用。

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; }
    }
}

但是如果我使用此方法退出cancelToken.ThrowIfCancellationRequested (); 得到一個錯誤:當Job()方法達到J == 50,並且調用worker.HardStop()函數時,程序窗口崩潰,並且我在該字符串上獲取並獲取異常“ OparetionCanceledException未由用戶代碼處理”

cancellationToken.ThrowIfCancellationRequested();

那么,怎么了? 據我了解,我已經將其放入try {} catch(){}中,應該在wtoken.Cancel()上的Task中更改某些布爾屬性(Task.IsCancelled == false,Task.IsFaulted == true);

我會避免所有與任務混在一起的事情,並為此使用Microsoft的Reactive Framework(NuGet“ Rx-Main”)。

這是如何做:

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();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM