我正在读一本描述SyncRoot模式的c#书籍。它显示了
void doThis()
{
lock(this){ ... }
}
void doThat()
{
lock(this){ ... }
}并与SyncRoot模式进行比较:
object syncRoot = new object();
void doThis()
{
lock(syncRoot ){ ... }
}
void doThat()
{
lock(syncRoot){ ... }
}但是,我并不真正理解这里的区别;似乎在这两种情况下,这两种方法一次只能由一个线程访问。
书中描述了..。因为实例的对象也可以用于从外部进行同步访问,并且您不能通过类本身来控制这一点,所以可以使用SyncRoot模式Eh?“实例的对象”?
有人能告诉我上面两种方法的区别吗?
发布于 2009-04-08 07:43:08
如果你有一个内部数据结构,你想防止多个线程同时访问,你应该总是确保你锁定的对象不是公共的。
这背后的原因是,公共对象可以被任何人锁定,因此您可以创建死锁,因为您不能完全控制锁定模式。
这意味着锁定this不是一个选项,因为任何人都可以锁定该对象。同样,您不应该锁定您向外部世界公开的东西。
这意味着最好的解决方案是使用内部对象,因此提示是只使用Object。
锁定数据结构是您真正需要完全控制的东西,否则您可能会设置死锁的场景,这可能会导致非常难以处理的问题。
发布于 2011-12-15 20:38:58
此模式的实际目的是实现与包装器层次结构的正确同步。
例如,如果类WrapperA包装了ClassThanNeedsToBeSynced的一个实例,而类WrapperB包装了ClassThanNeedsToBeSynced的相同实例,则不能锁定WrapperA或WrapperB,因为如果锁定WrapperA,则锁定WrappedB不会等待。出于这个原因,您必须锁定wrapperAInst.SyncRoot和wrapperBInst.SyncRoot,这两个锁将锁委托给ClassThanNeedsToBeSynced。
示例:
public interface ISynchronized
{
object SyncRoot { get; }
}
public class SynchronizationCriticalClass : ISynchronized
{
public object SyncRoot
{
// you can return this, because this class wraps nothing.
get { return this; }
}
}
public class WrapperA : ISynchronized
{
ISynchronized subClass;
public WrapperA(ISynchronized subClass)
{
this.subClass = subClass;
}
public object SyncRoot
{
// you should return SyncRoot of underlying class.
get { return subClass.SyncRoot; }
}
}
public class WrapperB : ISynchronized
{
ISynchronized subClass;
public WrapperB(ISynchronized subClass)
{
this.subClass = subClass;
}
public object SyncRoot
{
// you should return SyncRoot of underlying class.
get { return subClass.SyncRoot; }
}
}
// Run
class MainClass
{
delegate void DoSomethingAsyncDelegate(ISynchronized obj);
public static void Main(string[] args)
{
SynchronizationCriticalClass rootClass = new SynchronizationCriticalClass();
WrapperA wrapperA = new WrapperA(rootClass);
WrapperB wrapperB = new WrapperB(rootClass);
// Do some async work with them to test synchronization.
//Works good.
DoSomethingAsyncDelegate work = new DoSomethingAsyncDelegate(DoSomethingAsyncCorrectly);
work.BeginInvoke(wrapperA, null, null);
work.BeginInvoke(wrapperB, null, null);
// Works wrong.
work = new DoSomethingAsyncDelegate(DoSomethingAsyncIncorrectly);
work.BeginInvoke(wrapperA, null, null);
work.BeginInvoke(wrapperB, null, null);
}
static void DoSomethingAsyncCorrectly(ISynchronized obj)
{
lock (obj.SyncRoot)
{
// Do something with obj
}
}
// This works wrong! obj is locked but not the underlaying object!
static void DoSomethingAsyncIncorrectly(ISynchronized obj)
{
lock (obj)
{
// Do something with obj
}
}
}发布于 2009-04-08 07:45:24
下面是一个示例:
class ILockMySelf
{
public void doThat()
{
lock (this)
{
// Don't actually need anything here.
// In this example this will never be reached.
}
}
}
class WeveGotAProblem
{
ILockMySelf anObjectIShouldntUseToLock = new ILockMySelf();
public void doThis()
{
lock (anObjectIShouldntUseToLock)
{
// doThat will wait for the lock to be released to finish the thread
var thread = new Thread(x => anObjectIShouldntUseToLock.doThat());
thread.Start();
// doThis will wait for the thread to finish to release the lock
thread.Join();
}
}
}您可以看到,第二个类可以在lock语句中使用第一个类的实例。这会导致示例中的死锁。
正确的SyncRoot实现是:
object syncRoot = new object();
void doThis()
{
lock(syncRoot ){ ... }
}
void doThat()
{
lock(syncRoot ){ ... }
}因为syncRoot是一个私有字段,所以您不必担心这个对象的外部使用。
https://stackoverflow.com/questions/728896
复制相似问题