日期:2014-05-19  浏览次数:20806 次

多线程,怎么锁定对象?
今天学习多线程时,看到lock(this)可以锁定某段代码,msdn中介绍也可锁定对象,于是写了下面的代码,两个线程修改同一个标签的值,其中一个线程想要锁定label1,但是不成功,不知道问题在哪里,请高手指点,谢谢!

public   class   Form1   :   System.Windows.Forms.Form
{
private   System.Windows.Forms.Label   label1;

Thread   t1,   t2;


private   void   Form1_Load(object   sender,   System.EventArgs   e)
{
t1   =   new   Thread(new   ThreadStart(Method));
t2   =   new   Thread(new   ThreadStart(Method1));
t1.Name   =   "t1 ";
t2.Name   =   "t2 ";
t1.Start();
t2.Start();
}

public   void   Method()
{
lock(this.label1)
{
while(Convert.ToInt32(this.label1.Text)   >   0)
{
Thread.Sleep(300);
this.label1.Text   =   (Convert.ToInt32(this.label1.Text)   -   1).ToString();
}
}
}

public     void   Method1()
{
while(Convert.ToInt32(this.label1.Text)   >   0)
{
Thread.Sleep(300);
this.label1.Text   =   (Convert.ToInt32(this.label1.Text)   -   1).ToString();
}
}

private   void   Form1_Closing(object   sender,   System.ComponentModel.CancelEventArgs   e)
{
t1.Abort();
t2.Abort();
}
}

------解决方案--------------------
Method1也lock试试
public void Method1()
{
lock(this.label1)
{
while(Convert.ToInt32(this.label1.Text) > 0)
{
Thread.Sleep(300);
this.label1.Text = (Convert.ToInt32(this.label1.Text) - 1).ToString();
}
}
}
------解决方案--------------------
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。
而不是保证lock的对象不允许被其他线程访问或修改!

MSDN中有说明:
备注
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

线程处理(C# 编程指南) 这节讨论了线程处理。

lock 调用块开始位置的 Enter 和块结束位置的 Exit。

通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ( "myLock ") 违反此准则:

如果实例可以被公共访问,将出现 lock (this) 问题。

如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。

由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。

最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。

------解决方案--------------------
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;

Thread t1, t2;
Object lockerObj = new Object(); // This is lock.

private void Form1_Load(object sender, System.EventArgs e)
{
t1 = new Thread(new ThreadStart(Method));
t2 = new Thread(new ThreadStart(Method1));
t1.Name = "t1 ";
t2.Name = "t2 ";
t1.Start();
t2.Start();
}

public void Method()
{
lock(lockerObj)
{
while(Convert.ToInt32(this.label1.Text) > 0)
{
Thread.Sleep(300);
this.label1.Text = (Convert.ToInt32(this.label1.Text) - 1).ToString();
}
}
}

public void Method1()
{
lock(lockerObj )
{
while(Convert.ToInt32(this.label1.Text) > 0)
{
Thread.Sleep(300);
this.label1.Text = (Convert.T