您的位置:首页 > 其它

线程学习7——lock语句

2011-06-03 11:09 134 查看
什么是lock语句?

lock语句是设置锁定和解除锁定的一种简单方式。

为什么使用lock语句?

在使用多线程的过程中,会出现很多难以发现的问题,比如竞态条件与死锁,为了避免这些同步问题,所以使用lock语句,当然这并不是解决同步问题的唯一方法。

lock语句的作用:

lock

关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。
如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

lock语句的用法:


lock

关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
此语句的形式如下:

Object thisLock = new Object();

lock (thisLock)

{

// Critical code section.

}

lock语句的注意事项:

最佳做法是定义 private

对象来锁定, 或 private static

对象变量来保护所有实例所共有的数据。

通常,应避免锁定 public

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

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

第一种情况:

1.同一个对象,不同线程。lock (this) 不会出现问题的例子

class MyMainClass
{
private static readonly object lockHelper = new object();
private static int num = 0; //记录不同线程操作的次数
private int count = 0; //记录每个对象执行次数
static void Main()
{
//一个对象
MyMainClass c1 = new MyMainClass();
//两个线程
Thread myThread1 = new Thread(new ThreadStart(c1.DoSomething));
myThread1.Name = "FirstThread";
myThread1.Start();
Thread myThread2 = new Thread(new ThreadStart(c1.DoSomething));
myThread2.Name = "SecondThread";
myThread2.Start();
Console.WriteLine("C1 count: {0}", c1.count);
Console.ReadLine();
}
public void DoSomething()
{
//此处可以用this,或者也可以用lockHelper
lock (this)
{
while (num < 100)
{
num++;
Console.WriteLine("{0} add value: {1}", Thread.CurrentThread.Name, num);
count++;
}
}
}
}




2.不同对象,不同线程。lock (this) 会出现问题的例子

class MyMainClass
{
private static readonly object lockHelper = new object();
private static int num = 0; //记录不同线程操作的次数
private int count = 0; //记录每个对象执行次数
static void Main()
{
//两个对象
MyMainClass c1 = new MyMainClass();
MyMainClass c2 = new MyMainClass();
//两个线程
Thread myThread1 = new Thread(new ThreadStart(c1.DoSomething));
myThread1.Name = "FirstThread";
myThread1.Start();
Thread myThread2 = new Thread(new ThreadStart(c2.DoSomething));
myThread2.Name = "SecondThread";
myThread2.Start();
Console.WriteLine("C1 count: {0}", c1.count);
Console.WriteLine("C2 count: {0}", c2.count);
Console.ReadLine();
}
public void DoSomething()
{
//lock (this)
//此处只可以用lockHelper,若用this则锁不住
lock (lockHelper)
{
while (num < 100)
{
num++;
Console.WriteLine("{0} add value: {1}", Thread.CurrentThread.Name, num);
count++;
}
}
}
}




第二种情况:如果一个类是公有的时,应该避免在基方法或属性中使用lock(this)语句,因为如果有其他人使用你的组件,

它并不了解你的组件内部是否使用了锁,当组件内部使用了锁,而使用者又在类外部对类实例尝试加锁,则可能导致一个死锁。

例如:

public class InternalClass
{
.....
private void ThreadFunction()
{
......
lock (this)
{
......
}
}
}
public class ClassMain
{
private InternalClass theClass = new InternalClass();
public ClassMain()
{
lock (theClass) // 如果注释掉这句,ThreadFunction()中的lock将执行成功
{
Console.WriteLine("对象被锁定, 在这里我们获得了一个死锁...");
}
}
}
static void Main(string[] args)
{
ClassMain cm = new ClassMain();
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
因此,应尽量避免甚至拒绝使用lock(this)这样的语句。


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

lock (typeof (MyType))
Type t1 = typeof(MyType),
Type t2 = typeof(MyType),

这样的两个t1,t2,引用是相等的,跟lock(this)会产生同样的问题.


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

例如:

string a = "String Example";

string b = "String Example";

string c = (new StringBuilder()).Append("String Example").ToString();

Console.WriteLine("a==b? {0}", object.ReferenceEquals(a, b));

Console.WriteLine("a==c? {0}", object.ReferenceEquals(a, c));
上面程序执行的结果是:

a==b? True

a==c? False

从上面可以看出,a和b指向的是同一个引用,而lock正是通过引用来区分并加锁临界代码段的。也就是说,如果在我们一程序的一个部分中使用了
lock("thisLock")进行加锁,而在程序的另一个位置同样也使用lock("thisLock")进行加锁,则极有可能导致一个死锁,因而是
很危险的。实际上,不只是lock("thisLock")这样的语句,在lock中使用string类型的引用都有可能导致死锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: