关于线程同步(Lock)
来源:互联网 发布:7.16大连新港火灾知乎 编辑:程序博客网 时间:2024/05/17 00:29
一. 为什么要lock,lock了什么?
当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。lock是C#中最常用的同步方式,格式为lock(objectA){codeB} 。
lock(objectA){codeB} 看似简单,实际上有三个意思,这对于适当地使用它至关重要:
1. objectA被lock了吗?没有则由我来lock,否则一直等待,直至objectA被释放。
2. lock以后在执行codeB的期间其他线程不能调用codeB。
3. 执行完codeB之后释放objectA,并且codeB可以被其他线程访问。
二. lock(this)怎么了?
我们看一个例子:
using System;
using System.Threading;
namespace Namespace1
{
class C1
{
private bool deadlocked = true;
//这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
public void LockMe(object o)
{
lock (this)
{
while(deadlocked)
{
deadlocked = (bool)o;
Console.WriteLine("I am locked :(");
Thread.Sleep(500);
}
}
}
//所有线程都可以同时访问的方法
public void DoNotLockMe()
{
Console.WriteLine("I am not locked :)");
}
}
class Program
{
static void Main(string[] args)
{
C1 c1 = new C1();
//在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
Thread t1 = new Thread(c1.LockMe);
t1.Start(true);
Thread.Sleep(100);
//在主线程中lock c1
lock (c1)
{
//调用没有被lock的方法
c1.DoNotLockMe();
//调用被lock的方法,并试图将deadlock解除
c1.LockMe(false);
}
}
}
在t1线程中,LockMe调用了lock(this), 也就是Main函数中的c1,这时候在主线程中调用lock(c1)时,因为c1已经被锁定,所以必须要等待t1中的lock块执行完毕之后才能访问锁定的代码,即lock块中的所有操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。
把C1的代码稍作改动:
class C1
{
private bool deadlocked = true;
private object locker = new object();
//这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
public void LockMe(object o)
{
lock (locker)
{
while(deadlocked)
{
deadlocked = (bool)o;
Console.WriteLine("I am locked :(");
Thread.Sleep(500);
}
}
}
//所有线程都可以同时访问的方法
public void DoNotLockMe()
{
Console.WriteLine("I am not locked :)");
}
}
{
private bool deadlocked = true;
private object locker = new object();
//这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
public void LockMe(object o)
{
lock (locker)
{
while(deadlocked)
{
deadlocked = (bool)o;
Console.WriteLine("I am locked :(");
Thread.Sleep(500);
}
}
}
//所有线程都可以同时访问的方法
public void DoNotLockMe()
{
Console.WriteLine("I am not locked :)");
}
}
这次我们使用一个私有成员作为锁定变量(locker),在LockMe中仅仅锁定这个私有locker,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,主线程依然可以进入lock块并调用DoNotLockMe(),但LockMe()依然不能访问,原因是其中锁定的locker还没有被t1释放。
关键点:
1. lock(this)的缺点就是在一个线程(例如本例的t1)通过执行该类的某个使用"lock(this)"的方法(例如本例的LockMe())锁定某对象之后, 导致整个对象无法被其他线程(例如本例的主线程)访问 - 因为程序员可以在任何其他线程(例如本例的主线程)访问该类的时候使用类似lock(c1)的代码,因此我们在设计类的时候就最好未雨绸缪,而不是把负担留给用户。
2. 我们应该使用不影响其他操作和不会被外部对象锁定的的私有成员作为locker。
3. 在使用lock的时候,被lock的对象(locker)一定要是引用类型的,如果是值类型,将导致每次lock的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,C#编译器(3.5.30729.1)在编译时就会给出一个错误)。
- 关于线程同步(Lock)
- C#lock线程同步
- 同步,线程通信,lock
- 同步线程1(lock)
- 线程同步Lock
- 线程同步---同步锁(Lock)
- 线程同步lock and monitor
- 【java】同步,线程通信,lock
- Lock实现线程的同步
- c#线程同步(2)----lock
- 线程同步—synchronized & Lock
- 线程同步:synchronized和Lock
- java线程同步 Lock同步锁
- 线程LOCK机制和synchronized线程同步
- 同步——synchronized机制、Lock和Conditon机制和关于线程中断
- 线程(七)--线程同步-同步锁(Lock)
- 线程同步作业(一):Lock,monitor
- c#线程同步——lock
- 今天你尽全力冲刺了吗?!2
- 使用托管扩展性框架(MEF)创建可扩展应用的简介
- VS2008和2005的区别
- BD64中不能使用Message Type ARTMAS之解决.
- 源程序到CPU执行要经历的整个流程
- 关于线程同步(Lock)
- spring的控制反转
- SCCM 中的网络唤醒 (Wake on LAN)
- 两种查询数据库内第N条数据的方法
- Windows下如何将服务器目录映射到本地驱动器
- Siebel EAI: Create a account with EJB3.x using AccountAttachment Business Service
- LED
- 我们身处如此火热的一个时代--弄潮儿远远大于白领
- sprintf用法总结