C# 关于Task.Factory.StartNew

C# 关于Task.Factory.StartNew,c#,task,C#,Task,嗨,有时候,在txtLog中,有4行,应该是5行。有人知道为什么吗? 非常感谢……您的代码的第一个错误是这一行: 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 Syste

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

您的代码的第一个错误是这一行:

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

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

代码的另一个错误是这一行:

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

    }
}
Control.CheckForIllegalCrossThreadCalls = false;
同时执行该行的两个不同线程可以同时检索文本的当前值,将它们的新文本连接到该值,然后将结果重新分配给文本。无论哪个线程重新分配最后一个线程,都将覆盖前一个或多个线程试图写入的内容

如果您使用Control.Invoke来更新UI,即调用Log方法,那么所有代码都将强制返回到它所属的UI线程,并且您的竞态条件将在UI线程中以原子方式解决,从而防止此类并发访问错误。例如:

this.txtLog.Text += System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":" + content + "\r\n";
由@Peter编写的是更正确和正确的方法。但是,您可以使用c中的来同步对日志方法的多个调用

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

Task.Factory.StartNew(() => {
    string str = System.DateTime.Now.ToString("fff");
    Debug.WriteLine(str);
    Invoke((MethodInvoker)(() => Log(str)));
});

如果试图从差异线程访问UI控件,可能会出现异常。@Hybridzz:不会,因为他们已使用control禁用了跨线程异常。CheckForIllegalCrossThreadCalls=false;这不是解决问题的好办法,因为它留下了一个更基本的问题,即OP从错误的线程访问UI对象。