2013-02-21 39 views
3

我有一个从旧格式迁移到新格式的功能。我需要这发生在我的对象的构造函数中,但不是静态构造函数,因为需要一个参数。我怎样才能让一段代码只执行一次?如何使用多线程精确执行一段代码?

对于一些背景:

class Foo 
{ 
    public Foo(string bar) 
    { 
    ShouldOnlyExecuteOnce(bar); 
    } 
} 

,然后使用可能是(每行不同的线程)

var f = new Foo("bar"); 
var fb = new Foo("meh"); 
etc 

我怎样才能正确地守护 “ShouldOnlyExecuteOnce” 的方法?

因为这是一种“迁移”类型的函数,所以我希望创建的第一个对象“获胜”并将旧数据迁移到这个新对象中。后来构建的对象不应该试图执行此函数,即使它们的参数不同也可以。

+2

那么你有什么要发生的第二次调用构造函数,有可能引起不同的观点?摘要很难回答这个问题。 – 2013-02-21 17:15:17

+0

@JonSkeet编辑得更清晰 – Earlz 2013-02-21 17:16:59

回答

2

你可以使用双重检查锁定。

class Foo 
{ 
    private static bool ShouldOnlyExecuteOnceExecuted = false; 
    private static readonly object Locker = new object(); 

    public Foo(string bar) 
    { 
     SetShouldOnlyExecuteOnce(bar); 
    } 

    private void SetShouldOnlyExecuteOnce(string bar) 
    { 
     if(!ShouldOnlyExecuteOnceExecuted) 
     { 
      lock(Locker) 
      { 
       if(!ShouldOnlyExecuteOnceExecuted) 
       { 
        ShouldOnlyExecuteOnce(bar); 
        ShouldOnlyExecuteOnceExecuted = true; 
       } 
      } 
     } 
    } 
} 
+0

难道这不会导致瓶颈在哪里线程正在等待锁,只发现它已经执行? – Earlz 2013-02-21 17:26:48

+0

@Earlz最初,只要设置了ShouldOnlyExecuteOnceExecuted,那么就不会有任何锁定。 – Romoku 2013-02-21 17:28:55

0

单例模式应该可以工作。

Parrotting乔恩斯基特:http://csharpindepth.com/articles/general/singleton.aspx

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    // Explicit static constructor to tell C# compiler 
    // not to mark type as beforefieldinit 
    static Singleton() 
    { 
    } 

    private Singleton() 
    { 
    } 

    public static Singleton Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 
} 

辛格尔顿的构造一次。虽然,关于传递新字符串值的部分可能会造成问题。所有连续呼叫都会忽略此值吗?

+0

IMO这会更好,作为评论.. – 2013-02-21 17:18:35

+1

一旦get访问器已经解雇了线程安全。 - >这不是线程安全的。 – 2013-02-21 17:21:54

+0

请参阅http://csharpindepth.com/articles/general/singleton.aspx以获取正确的线程安全单例实现 – DiskJunky 2013-02-21 17:26:57

0

我不知道,但我猜/尝试:

1 - 静态类充当一个包装,并调用你的方法在静态构造函数

2 - 一些IoC容器?

3 - Singleton?

4 - Lock?

5 - 以上都是?

0

我同意P.Brian,这似乎是一个单身模式。你可以在这里看到一篇很好的文章http://csharpindepth.com/articles/general/singleton.aspx,它很好地分解了它。通常最好的解决方案是#4;

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    // Explicit static constructor to tell C# compiler 
    // not to mark type as beforefieldinit 
    static Singleton() 
    { 
    } 

    private Singleton() 
    { 
    } 

    public static Singleton Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 
} 
+0

这不是线程安全的。 – 2013-02-21 17:25:58

+2

@UdoKlein是的,它是。阅读文章,找出原因。 – DiskJunky 2013-02-21 17:27:43

+0

@UdoKlein这实际上是。显式声明静态构造函数可确保将静态字段初始化为序言。 – Alex 2013-02-21 17:27:50

0

我一般会建议对实施细微机制,如双重检查锁定,尤其是当你已经有了他们在BCL实现。在这种情况下:

public class SafeInitializater 
{ 
    private bool _initialized; 
    private object _dummy; 
    private object _syncLock; 

    public void InitializeOnce(Action initializer) 
    { 
     LazyInitializer.EnsureInitialized(ref _dummy, ref _initialized, ref _syncLock, 
      () => { 
       initializer(); 
       return null; 
      }); 
    } 
} 

用法示例:

var initializer = new SafeInitializater(); //or you could make this static somewhere 

var t1 = Task.Run(() => 
{ 
    Console.WriteLine($"Task {Task.CurrentId} entering the race"); 
    initializer.InitializeOnce(() => Console.WriteLine($"Task {Task.CurrentId} won!")); 
}); 
var t2 = Task.Run(() => 
{ 
    Console.WriteLine($"Task {Task.CurrentId} entering the race"); 
    initializer.InitializeOnce(() => Console.WriteLine($"Task {Task.CurrentId} won!")); 
}); 

await Task.WhenAll(t1, t2); 
相关问题