xxxxxxxxxxxx
aaaaaaaaaaaa
xxxxxxxxxxxx
aaaaaaaaaaaa
// 将第二行“lt.testc(textBox1)”注释上,连续点击两次按钮,输出如下:
xxxxxxxxxxxx
xxxxxxxxxxxx
aaaaaaaaaaaa
aaaaaaaaaaaa
看起来好像lock没有起作用,为什么?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private LockTest lt = new LockTest();
private void button1_Click(object sender, EventArgs e)
{
lt.testc(textBox1);
lt.testc(textBox1); // 把此行注释上,连续点两次button1按钮,发现lock没有锁住
}
}
public class LockTest
{
private static object locker = new object();
public void testc(TextBox tb)
{
lock (locker)
{
tb.Invoke(new Action(() => tb.AppendText(“xxxxxxxxxxxx\r\n”)));
var sw = new Stopwatch();
sw.Start();
while (sw.ElapsedMilliseconds < 2000)
{
Thread.Sleep(1);
Application.DoEvents();
}
tb.Invoke(new Action(() => tb.AppendText(“aaaaaaaaaaaa\r\n”)));
}
}
}
20
例如:
void A() { lock (locker) { lock(locker) { // 可以运行到这里。 } } }
而 Application.DoEvents会运行UI的消息循环:
public void testc(TextBox tb) { // ... Application.DoEvents(); // ... }
UI的消息循环的结果就是 button1_Click有机会得到运行。
因此,出现了在UI线程下的button1_Click嵌套运行,而按照lock的分析,同一个线程下的lock是可以直接获得的。
5
原因是你这里写的while (sw.ElapsedMilliseconds < 2000) 两秒呀。只要连续的两次操作没有超过2秒就不会执行tb.Invoke(new Action(() => tb.AppendText(“aaaaaaaaaaaa\r\n”)));
10
lock (locker) { tb.Invoke(new Action(() => tb.AppendText("xxxxxxxxxxxx\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(1); Application.DoEvents(); } tb.Invoke(new Action(() => tb.AppendText("aaaaaaaaaaaa\r\n"))); }
下次发的时候。带上标签,否则很难看。
本人是这么理解的。不知道说的对不对,假如不注释,很容易理解。就是while函数阻止了第二个方法的运行。这个你应该可以理解。lock关键字根本就没用。去掉lock关键字也是一样的效果。
注释掉点两次的话。lock本人觉得还是起作用的,这里关键是这个Application.Doevent()函数。看过msdn的解释。说实在的很不形象,本人个人是这么理解的。这个函数执行的时候,就算有长方法使得界面假死,也可以允许其他控件或信息进行操作。而已经在运行的长时间程序会被暂停。下面是本人的测试例子:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private LockTest lt = new LockTest(); private void button1_Click_1(object sender, EventArgs e) { lt.testc(textBox1); } private void button2_Click(object sender, EventArgs e) { lt.testb(textBox1); } } public class LockTest { private static object locker = new object(); public void testc(TextBox tb) { lock (locker) { tb.Invoke(new Action(() => tb.AppendText("aaaa\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(1); Application.DoEvents(); } tb.Invoke(new Action(() => tb.AppendText("axaxax\r\n"))); } } public void testb(TextBox tb) { lock (locker) { tb.Invoke(new Action(() => tb.AppendText("bbbb\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(1); Application.DoEvents(); } tb.Invoke(new Action(() => tb.AppendText("bxbxbx\r\n"))); } } }
为了区分两个长时间方法,本人用了两个方法,被一个锁lock。点击第一个运行第二个方法,这个时候点击第二个按钮,第一个方法会被暂停。去执行第二个方法。当第二个方法执行完的时候,第一个方法才会被执行。
当然也看出来了。去掉lock。程序表现是一样的。
所以~~~题主的问题跟DoEvent()函数看似是没关系的。
接下来本人就开始想为什么被lock之后,语句还是可以执行呢。(就是连续点击两次。textbox的异步修改功能是重复出现的)想了一下。觉得还是Doenvent的问题。于是本人又修改了代码。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private LockTest lt = new LockTest(); private void button1_Click_1(object sender, EventArgs e) { lt.testc(textBox1,label1); } private void button2_Click(object sender, EventArgs e) { lt.testb(textBox1,label2); } } public class LockTest { private static object locker = new object(); private int count = 1; public void testc(TextBox tb,Label lable) { lock (locker) { tb.Invoke(new Action(() => tb.AppendText("aaaa\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(100); lable.Text = count.ToString(); count++; Application.DoEvents(); } tb.Invoke(new Action(() => tb.AppendText("axaxax\r\n"))); } } public void testb(TextBox tb,Label lable) { lock (locker) { tb.Invoke(new Action(() => tb.AppendText("bbbb\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(100); lable.Text = count.ToString(); count++; Application.DoEvents(); } tb.Invoke(new Action(() => tb.AppendText("bxbxbx\r\n"))); } } }
这下就很清楚了。还是Doenvet的问题!这个函数,通俗来说。就是当他运行的时候,你可以用程序处理其他消息队列中的事情。但是只要处理,那么现在的消息就往后推~~~~其实就是把现在的线程和正在处理的消息分开,处理你让他的处理的另外一个消息。lock还是起了作用。但是被这个函数直接把线程干掉了。
5
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private LockTest lt = new LockTest(); private void button1_Click_1(object sender, EventArgs e) { Task t = new TaskFactory().StartNew(() => lt.testc(this.textBox1,this.label1)); } private void button2_Click(object sender, EventArgs e) { Task t = new TaskFactory().StartNew(() => lt.testb(this.textBox1, this.label2)); } } public class LockTest { private static object locker = new object(); private int count = 1; public void testc(TextBox tb,Label lable) { lock (locker) { tb.Invoke(new Action(() => tb.AppendText("aaaa\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(100); lable.Invoke(new Action(() => lable.Text = count.ToString())); count++; } tb.Invoke(new Action(() => tb.AppendText("axaxax\r\n"))); } } public void testb(TextBox tb,Label lable) { lock (locker) { tb.Invoke(new Action(() => tb.AppendText("bbbb\r\n"))); var sw = new Stopwatch(); sw.Start(); while (sw.ElapsedMilliseconds < 2000) { Thread.Sleep(100); lable.Invoke(new Action(() => lable.Text = count.ToString())); count++; } tb.Invoke(new Action(() => tb.AppendText("bxbxbx\r\n"))); } } }
刚修改了一下。这样就能看出。lock还是有用的。