我正在开展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);
}
}
}
});
答案 0 :(得分:0)
任务的安排由TaskScheduler处理,并且无保证 t1
将被安排执行 {{1 }}
由于您用来定义将在t2
和Action
中运行的t1
的两个lambda关闭同一个变量 {{1你可能正在遇到一个
race condition:
t2
默认为== 0 inputMax
inputMax
首先开始执行,default(int)
t2
中,while中的条件为false,执行停止添加一些日志记录以自行查看此情况
您的程序逻辑似乎也存在一些缺陷,因为看起来inputMax==0
可以更快地耗尽项目数量,然后t2
就可以生成它们(取决于您的睡眠时间)使用)。
除非您特别想要遇到竞争条件,否则我认为您应该t2
使用Task.Run而{39}使用Task.ContinueWith
最后一点,即使您使用interlocked从线程安全的方式设置t1
来自不同的线程 - 仍然在条件中使用一个计数器不是一个好的同步策略。
如果你仍然需要通过共享状态(不是最好的方式)协调线程 - 你可以在t1
和inputMax
开始之前计算一个计数器 - 并传递值两个任务独立,并利用某种形式的等待(睡眠/旋转),本着producer-consumer的精神阻止消费者的一部分 - 因为t1
必须知道何时停止等待输入/消息强>
其他选项可以是 - 顺序运行任务(使用ContinueWith)或使用线程信令技术与EventWaitHandle子类之一。
答案 1 :(得分:0)
我能想到的一个问题是两个任务中使用的t2
变量并且线程安全。
您应该使用t2
类来正确行事。有关课程here的更多信息。