关于Task.Factory.StartNew

时间:2017-08-22 01:49:19

标签: c# task

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiThreadLog
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;

            for (int i = 0; i < 5; i++)
            {
                Task.Factory.StartNew(() => {
                    string str = System.DateTime.Now.ToString("fff");
                    Debug.WriteLine(str);
                    Log(str);
                });
            }

        }

        void Log(string content)
        {

            this.txtLog.Text += System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":" + content + "\r\n";
            this.txtLog.Focus();
            this.txtLog.Select(this.txtLog.TextLength, 0);
            this.txtLog.ScrollToCaret();
        }

    }
}

嗨,有时候,在txtLog中,有4行,应该是5行。有谁知道为什么? 非常感谢............................................... .................................................. ................

2 个答案:

答案 0 :(得分:4)

您的代码首先出现的问题是这一行:

20170822-13:56:02 :  50 ms

20170822-13:56:03 :  36 ms

20170822-13:56:03 :  59 ms

20170822-13:56:03 :  40 ms

20170822-13:56:03 :  67 ms

这种例外是有原因的。它可以帮助您避免编写错误的代码,即从拥有该对象的线程以外的线程访问UI对象的代码。不要那样做。

你的代码出现问题的另一个问题是这一行:

Control.CheckForIllegalCrossThreadCalls = false;

同时执行该行的两个不同线程可以(并且在您的情况下)同时检索this.txtLog.Text += System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":" + content + "\r\n"; 的当前值,将其新文本连接到该文本,然后将结果重新分配给{{ 1}}。无论哪个线程重新分配最后的胜利,都要覆盖先前线程(或多个线程)试图写入的内容。

如果您使用Text更新UI(即调用Text方法),那么所有代码​​将被强制回到它所属的UI线程,您的竞争条件将是在UI线程内原子地解决,防止这种并发访问错误。 E.g:

Control.Invoke()

答案 1 :(得分:0)

@Peter的

Answer更正确,更正确。但您可以使用c#中的lock来同步对日志方法的多个调用。

lock关键字通过获取给定对象的互斥锁,执行语句,然后释放锁来将语句块标记为关键部分。

Log()