如何在多线程环境中只执行一次代码块?

8
以下代码块展示了如何用C#加载对象。
public bool IsModelLoaded { get; set; }
public override MyObject Load()
{
    if (!IsModelLoaded)
    {
        Model = MyService.LoadMyObject(Model);
        IsModelLoaded = true;
    }
    return Model;
}

我想要这个代码块只运行一次,并且仅加载一次Model。然而,这个代码块会从两个不同的线程中运行两次。

我该如何确保这个代码块只在多个线程中运行一次?

7个回答

4
使用 Lazy<T> 类
private readonly Lazy<MyObject> myObject;

public MyClass()
{
    myObject = new Lazy<MyObject>(() =>
    {
        return MyService.LoadMyObject();
    }, LazyThreadSafetyMode.ExecutionAndPublication);
}

public bool IsModelLoaded
{
    get { return myObject.IsValueCreated; }
}

public override MyObject Load()
{
    return myObject.Value;
}

2
最简单的方法是添加。
[MethodImpl(MethodImplOptions.Synchronized)]
public override MyObject Load()
{
   //snip
}

但是需要注意的是,这会对整个对象进行锁定,而不仅仅是该方法。这并不是一个很好的做法。
参考链接:http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions.aspx 同步
指定该方法一次只能由一个线程执行。静态方法锁定类型,而实例方法锁定实例。任何实例函数中只能有一个线程执行,任何类的静态函数中也只能有一个线程执行。

2

我正在尝试实现单例模式。但是你的版本不是线程安全的。在这里阅读更多信息:http://www.dofactory.com/Patterns/PatternSingleton.aspx。请尝试使用以下实现:

public sealed class Singleton
{
    static Singleton instance=null;
    static readonly object padlock = new object();

    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            lock (padlock)
            {
                if (instance==null)
                {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }
}

2
如果您想编写线程安全的代码并确保块仅运行一次,可以按以下方式编写:
private System.Object lockThis = new System.Object(); 
public override MyObject Load()
{
    lock (lockThis) {
        if (!IsModelLoaded)
        {
            Model = MyService.LoadMyObject(Model);
            IsModelLoaded = true;
        }
    }
    return Model;
}

1
Action myCodeBlock = ()=>
{
  //do your job
  //...
  myCodeBlock = ()=>{};
}

在调用myCodeBlock()一次后,它将被一个什么都不做的方法重写。你仍然需要确保这个方法被安全地调用 - 使用lock或其他方式。


1

-1
创建一个静态对象(比如布尔类型),通过将其放在if语句中来确定代码是否已执行:)
编辑:我不确定这是否是线程安全的,所以它可能不适合您的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接