任务有时开始,有时不开始,为什么?如何修改它?

时间:2017-08-05 10:21:33

标签: .net winforms task

我正在开展winForm项目,我在表单中添加了listBox,名为listBox1。 代码如下:

private int inputMax;
private void button1_Click(object sender, EventArgs e)
{
    Task t1 = Task.Run(() =>
    {
        string[] input = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "end" };
        inputMax = input.Length;
        foreach (string s in input)
        {
            Thread.Sleep(new Random().Next(1000, 2001));
            if (listBox1.InvokeRequired)
            {
                listBox1.Invoke(new Action(() => listBox1.Items.Add(s)));
            }
        }

    });

    Task t2 = Task.Run(() => //t2 sometimes not start
    {
        while (inputMax > 0)
        {
            Thread.Sleep(2000);
            if (listBox1.InvokeRequired)
            {
                if ((int)listBox1.Invoke(new Func<int>(() => listBox1.Items.Count)) > 0)
                {
                    listBox1.Invoke(new Action(() => listBox1.Items.RemoveAt(0)));
                    inputMax--;
                }
            }

        }

    });

}
t2,有时候没有开始,为什么?如何修改?谢谢!

运行环境:windows10,.NET4.5.1

有一个问题:在t1和t2之间加上一个MessageBox.Show(&#34;一些字符串&#34;);该程序也可以正常工作,这是为什么?

Task t1 = Task.Run(() =>
    {
        string[] input = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "end" };
        Interlocked.Exchange(ref inputMax, input.Length);
        foreach (string s in input)
        {
            createLog(@"F:\tasklog.txt", "t1---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "---inputMax:"+inputMax.ToString()+ "\r\n");
            Thread.Sleep(new Random().Next(1000, 2001));
            if(listBox1.InvokeRequired)
            {
                listBox1.Invoke(new Action(() => listBox1.Items.Add(s)));
            }
        }

    });

MessageBox.Show("some string"); //Add this,the progaram can work properly,why?

Task t2 = Task.Run(() =>
    {
        while(inputMax>0)
        {
            createLog(@"F:\tasklog.txt", "t2---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "---inputMax:"+inputMax.ToString()+"\r\n");
            Thread.Sleep(2000);
            if(listBox1.InvokeRequired)
            {
                if ((int)listBox1.Invoke(new Func<int>(() => listBox1.Items.Count)) > 0)
                {
                    listBox1.Invoke(new Action(() => listBox1.Items.RemoveAt(0)));
                    Interlocked.Decrement(ref inputMax);

                }
            }

        }

    });

2 个答案:

答案 0 :(得分:0)

任务的安排由TaskScheduler处理,并且无保证 t1将被安排执行 {{1 }}

由于您用来定义将在t2Action 中运行的t1的两个lambda关闭同一个变量 {{1你可能正在遇到一个 race condition

  1. t2默认为== 0 inputMax
  2. inputMax首先开始执行,default(int)
  3. t2中,while中的条件为false,执行停止
  4. 添加一些日志记录以自行查看此情况

    您的程序逻辑似乎也存在一些缺陷,因为看起来inputMax==0可以更快地耗尽项目数量,然后t2就可以生成它们(取决于您的睡眠时间)使用)。

    除非您特别想要遇到竞争条件,否则我认为您应该t2使用Task.Run而{39}使用Task.ContinueWith

    最后一点,即使您使用interlocked从线程安全的方式设置t1来自不同的线程 - 仍然在条件中使用一个计数器不是一个好的同步策略。

    如果你仍然需要通过共享状态(不是最好的方式)协调线程 - 你可以在t1inputMax开始之前计算一个计数器 - 并传递值两个任务独立,并利用某种形式的等待(睡眠/旋转),本着producer-consumer的精神阻止消费者的一部分 - 因为t1必须知道何时停止等待输入/消息

    其他选项可以是 - 顺序运行任务(使用ContinueWith)或使用线程信令技术与EventWaitHandle子类之一。

答案 1 :(得分:0)

我能想到的一个问题是两个任务中使用的t2变量并且线程安全

您应该使用t2类来正确行事。有关课程here的更多信息。