【问题标题】:How to execute a block of code only once on a multithreading environment?如何在多线程环境中只执行一次代码块?
【发布时间】:2021-11-25 23:22:16
【问题描述】:

以下代码块在 C# 中执行对象的加载。

public bool IsModelLoaded { get; set; }
public override MyObject Load()
{
    if (!IsModelLoaded)
    {
        Model = MyService.LoadMyObject(Model);
        IsModelLoaded = true;
    }
    return Model;
}

我的意图是只运行一次这个块,因此只加载一次Model。然而,这个代码块从 2 个不同的线程运行了两次。

如何确保此块只运行一次? (在多个线程上)。

【问题讨论】:

    标签: c# wpf multithreading thread-safety


    【解决方案1】:

    使用Lazy<T> Class

    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

      同步

      指定该方法一次只能由一个线程执行。静态方法锁定类型,而实例方法锁定实例。任何实例函数中只能有一个线程执行,类的任何静态函数中只能有一个线程执行。

      【讨论】:

        【解决方案3】:

        我正在尝试实现singleton 模式。但是您的版本不是线程安全的。在此处阅读更多信息: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;
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案4】:

          如果你想编写线程安全的代码并确保块只运行一次,你可以这样写:

          private System.Object lockThis = new System.Object(); 
          public override MyObject Load()
          {
              lock (lockThis) {
                  if (!IsModelLoaded)
                  {
                      Model = MyService.LoadMyObject(Model);
                      IsModelLoaded = true;
                  }
              }
              return Model;
          }
          

          【讨论】:

            【解决方案5】:
            Action myCodeBlock = ()=>
            {
              //do your job
              //...
              myCodeBlock = ()=>{};
            }
            

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

            【讨论】:

              【解决方案6】:

              【讨论】:

                【解决方案7】:

                创建一个静态对象(如布尔值),通过将其放入 if 语句中来确定代码是否已运行 :)

                编辑:我不确定这是否是线程安全的,所以它可能不是你的解决方案。

                【讨论】:

                  猜你喜欢
                  • 2017-09-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-06-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多