首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SyncRoot模式有什么用?

SyncRoot模式有什么用?
EN

Stack Overflow用户
提问于 2009-04-08 07:37:53
回答 4查看 33.4K关注 0票数 71

我正在读一本描述SyncRoot模式的c#书籍。它显示了

代码语言:javascript
复制
void doThis()
{
    lock(this){ ... }
}

void doThat()
{
    lock(this){ ... }
}

并与SyncRoot模式进行比较:

代码语言:javascript
复制
object syncRoot = new object();

void doThis()
{
    lock(syncRoot ){ ... }
}

void doThat()
{
    lock(syncRoot){ ... }
}

但是,我并不真正理解这里的区别;似乎在这两种情况下,这两种方法一次只能由一个线程访问。

书中描述了..。因为实例的对象也可以用于从外部进行同步访问,并且您不能通过类本身来控制这一点,所以可以使用SyncRoot模式Eh?“实例的对象”?

有人能告诉我上面两种方法的区别吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-04-08 07:43:08

如果你有一个内部数据结构,你想防止多个线程同时访问,你应该总是确保你锁定的对象不是公共的。

这背后的原因是,公共对象可以被任何人锁定,因此您可以创建死锁,因为您不能完全控制锁定模式。

这意味着锁定this不是一个选项,因为任何人都可以锁定该对象。同样,您不应该锁定您向外部世界公开的东西。

这意味着最好的解决方案是使用内部对象,因此提示是只使用Object

锁定数据结构是您真正需要完全控制的东西,否则您可能会设置死锁的场景,这可能会导致非常难以处理的问题。

票数 76
EN

Stack Overflow用户

发布于 2011-12-15 20:38:58

此模式的实际目的是实现与包装器层次结构的正确同步。

例如,如果类WrapperA包装了ClassThanNeedsToBeSynced的一个实例,而类WrapperB包装了ClassThanNeedsToBeSynced的相同实例,则不能锁定WrapperA或WrapperB,因为如果锁定WrapperA,则锁定WrappedB不会等待。出于这个原因,您必须锁定wrapperAInst.SyncRoot和wrapperBInst.SyncRoot,这两个锁将锁委托给ClassThanNeedsToBeSynced。

示例:

代码语言:javascript
复制
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
        }
    }
}
票数 19
EN

Stack Overflow用户

发布于 2009-04-08 07:45:24

下面是一个示例:

代码语言:javascript
复制
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实现是:

代码语言:javascript
复制
object syncRoot = new object();

void doThis()
{
    lock(syncRoot ){ ... }
}

void doThat()
{
    lock(syncRoot ){ ... }
}

因为syncRoot是一个私有字段,所以您不必担心这个对象的外部使用。

票数 18
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/728896

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档