对多线程应用程序中的按钮单击没有影响

时间:2017-02-28 13:15:19

标签: c# multithreading winforms

除停止按钮外,一切正常。 (按钮3和按钮4 OnClick):

我制作了一个有四个按钮的应用程序。

这是一个多线程应用程序。

按钮1和2将开始产生线程。

按钮3和4将分别停止该过程。

但它似乎不起作用。

这是我的代码:

public partial class Form1: Form
{
    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    CancellationToken token;

    public Form1()
    {
        InitializeComponent();
        token = cancellationTokenSource.Token;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task t = Task.Run(() =>
        {
            while (true)
            {
                for (int i = 0; i < 100; i++)
                {
                    System.Threading.Thread.Sleep(1000);
                    Action act = () => textBox1.Text = Convert.ToString(i);
                    textBox1.Invoke(act);
                }
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                } 
            }
        }, token);
        }

    private void button2_Click(object sender, EventArgs e)
    {
        //token.Cancel();
    }

    private void button3_Click(object sender, EventArgs e)
    {
        Task t1 = Task.Run(() =>
        {
            while (true)
            {
                for (int i = 0; i < 100; i++)
                {
                    System.Threading.Thread.Sleep(1000);
                    Action act = () => textBox2.Text = Convert.ToString(i);
                    textBox2.Invoke(act);
                }
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                } 
            }
        }, token);
    }

    private void button4_Click(object sender, EventArgs e)
    {
        //token.Cancel();
    }
}

更新

这是更新后的代码:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiThreading_Start_Stop_Counter
{
public partial class Form1 : Form
{
    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    CancellationToken token;
    CancellationTokenSource cancellationTokenSource1 = new CancellationTokenSource();
    CancellationToken token1;

    public Form1()
    {
        InitializeComponent();
        token = cancellationTokenSource.Token;
        token1 = cancellationTokenSource1.Token;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task t = Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                }
                // your code
                System.Threading.Thread.Sleep(1000);
                Action act = () => textBox1.Text = Convert.ToString(i);
                textBox1.Invoke(act);
            }
        });
        }

    private void button2_Click(object sender, EventArgs e)
    {
        cancellationTokenSource.Cancel();
    }

    private void button3_Click(object sender, EventArgs e)
    {
        Task t1 = Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                if (token1.IsCancellationRequested)
                {
                    token1.ThrowIfCancellationRequested();
                }
                // your code
                System.Threading.Thread.Sleep(1000);
                Action act = () => textBox2.Text = Convert.ToString(i);
                textBox2.Invoke(act);
            }
        });
    }

    private void button4_Click(object sender, EventArgs e)
    {
        cancellationTokenSource1.Cancel();
    }
}
}

现在任务正在取消,但有这个例外:

mscorlib.dll中出现“System.OperationCanceledException”类型的异常,但未在用户代码中处理 附加信息:操作已取消。

解决:

循环时使用。谢谢!

3 个答案:

答案 0 :(得分:0)

  • 取消方法属于CancellationTokenSource,因此您无法在CancellationToken
  • 上调用它
  • if(token.IsCancellationRequested)仅在100秒后被调用,所以也许你没等多久或者更多可能把支票放在错误的地方

答案 1 :(得分:0)

正如@Roman所说,

如果在不同的任务中请求了令牌,则应为每个println "${mainUrl}${it.replaceAll('\\s','%')}/config.xml" 创建一个新的CancellationTokenSource

CancellationToken

制作两个不同的CancellationTokenSource cancellationTokenSource1, cancellationTokenSource2; CancellationToken token1, token2; CancellationTokenSource

在for循环或while循环中使用它们,如下所示,具体取决于您的取消情况。

CancellationToken

或者

for (int i = 0; i < 100; i++)
{
    if (token1.IsCancellationRequested)
    {
        token1.ThrowIfCancellationRequested();
    }
    // your code
    System.Threading.Thread.Sleep(1000);
    Action act = () => textBox1.Text = Convert.ToString(i);
    textBox1.Invoke(act);
}

答案 2 :(得分:0)

检查令牌是否被取消的部分应放在for循环中。

for (int i = 0; i < 100; i++)
{
     if (token.IsCancellationRequested)
     {
         token.ThrowIfCancellationRequested();
     }
     System.Threading.Thread.Sleep(1000);
     Action act = () => textBox1.Text = Convert.ToString(i);
     textBox1.Invoke(act);
}

另外你抛出OperationCanceledException并且没有抓住它。

如果您不想处理异常,可以为while循环引入一些变量,如:

Task t = Task.Run(() =>
        {
            var run = true;
            while (run)
            {
                for (int i = 0; i < 100; i++)
                {
                    if (token.IsCancellationRequested)
                    {
                        run = false;
                        break;
                    }
                   //loop code
                } 
            }
        }, token);

button2应包含取消令牌的代码 cancellationTokenSource.Cancel();

对于按钮3和4,您需要不同的CancellationTokenSource和CancellationToken。