Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 阻止线程繁殖_C#_Multithreading_Asynchronous - Fatal编程技术网

C# 阻止线程繁殖

C# 阻止线程繁殖,c#,multithreading,asynchronous,C#,Multithreading,Asynchronous,在Windows窗体中具有下面的代码 private bool test = false; private async void button1_Click(object sender, EventArgs e) { await Task.Run(() => { test = !test ; textBox2.Text = test.ToString(); // Each time i

在Windows窗体中具有下面的代码

    private bool test = false;

    private async void button1_Click(object sender, EventArgs e)
    {
        await Task.Run(() =>
        {
            test = !test ;
            textBox2.Text = test.ToString(); // Each time i click text box switches to true and false
            for (int i = 0; i < 1000000; i++)
            {
                textBox1.Text = i.ToString();
            }
        });

       textBox2.Text = "Done"; // This will never happen until the task is done
    }
private bool test=false;
私有异步无效按钮1\u单击(对象发送方,事件参数e)
{
等待任务。运行(()=>
{
测试=!测试;
textBox2.Text=test.ToString();//每次单击时,文本框都会切换为true和false
对于(int i=0;i<1000000;i++)
{
textBox1.Text=i.ToString();
}
});
textBox2.Text=“Done”;//在任务完成之前,这种情况永远不会发生
}
如果单击按钮,文本框文本将从0更改为1000000

因为我使用异步/等待。表单不会冻结,我可以看到文本框从0到1000000计数

但问题是,如果我再次单击该按钮,则会生成另一个线程,textbox值会更改两个线程。您可以看到两个线程中的两个计数器正在更改textbox值

如果再次单击,则会得到3个线程、4个线程等…textbox2也会更改为true、false、true

这对我来说只是一个测试,看看async await实际上是如何工作的

但我认为我用错了。我担心如果我在项目中使用async,最终会出现这种情况

如何停止从单个异步方法生成线程

目前,我认为每次按下按钮都会产生新的异步方法

这是我看到的


按下按钮后禁用该按钮,并在按钮完成后启用。

评论中对正在发生的事情有一些混淆。特别是因为发布的代码实际上不应该工作(它不是线程安全的)

最简单的复制方法(在表单上放置按钮和标签):

private async void按钮1\u单击(对象发送方,事件参数)//添加异步
{
对于(int i=0;i<1000;i++)
{
标签1.Text=”“+i;
等待任务。延迟(100);
}
}
您可以让它一次运行多个循环,您可以增加延迟以更好地看到这一点。请注意,没有涉及额外的线程,所有线程都在主GUI线程上运行

这里的键是
async
wait
,它们使编译器将对该方法的调用转换为状态机,这样它就可以一次交错执行多个循环。可以将其视为一种可以在
wait
调用时暂停并稍后恢复的方法。都在同一条线上

更重要的是,它将循环与主线程交错,以便继续处理输入消息并更新屏幕

这就是为什么


如何解决这一问题取决于您实际需要什么,现在从@CSharpie删除的答案显示了基本模式:使用布尔字段作为保护,或者禁用并启用按钮

还是说吧。最好的办法是。因为我所做的是错误的编码风格。异步方法就是这样做的。用户界面应该根据最终结果而不是多任务来更新。非常感谢。我不知道我能像这样运行这个方法。异步与我的想法完全不同。并且从Task.Run.com开始,仅对事件处理程序使用
async void
模式。在其他地方,使用
异步任务
。这是完全不同的代码。我已经知道这是可能的,但是您正在UI线程上运行分配,并且没有
任务。运行
。在OP的代码中,要么整个lambda在单独的线程上运行(在这种情况下,它们应该得到一个错误),要么不是(在这种情况下,它们不应该看到竞争线程)。我感兴趣的是OP的代码是如何导致他们所描述的行为的。@Asad-你一路上遇到了一个不同的问题。您可以在调试器之外运行原始代码(Ctrl+F5)。它不是线程安全的,但当您以这种方式禁用检查时,不会发生可怕的事情。这个答案显示了线程安全(无线程)版本显示了相同的核心问题。啊,好吧,这更有意义。我没有意识到只有在调试模式下才会发生这种异常。
private async void button1_Click(object sender, EventArgs e)   // add the async
{
    for (int i = 0; i < 1000; i++)
    {
        label1.Text = "" + i;
        await Task.Delay(100);
    }
}