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