如何在考虑多线程的情况下执行一段代码?

时间:2013-02-21 17:13:44

标签: c# .net multithreading thread-safety locking

我有一个从旧格式“迁移”到新格式的功能。我需要在我的对象的构造函数中发生这种情况,而不是静态构造函数,因为需要参数。如何让一段代码只执行一次?

对于某些情况:

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

然后使用可能是(每行都有一个不同的线程)

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

如何正确保护“ShouldOnlyExecuteOnce”方法?

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

7 个答案:

答案 0 :(得分:3)

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

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;
                }
            }
        }
    }
}

答案 1 :(得分:0)

Singleton模式应该有效。

Parrotting Jon Skeet: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;
         }
     }
 } 

Singleton's构造一次。虽然,关于传递新字符串值的部分可能会出现问题。是否在所有连续呼叫中忽略此值?

答案 2 :(得分:0)

你需要一个互斥锁。这正是用于设计互斥锁的用例。

http://www.dotnetperls.com/mutex

答案 3 :(得分:0)

答案 4 :(得分:0)

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

1 - 作为包装器的静态类,在静态构造函数中调用您的方法

2 - 一些IoC容器?

3 - 单身人士?

4 - 锁?

5 - 以上全部?

答案 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;
        }
    }
} 

答案 6 :(得分: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);