Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute a block of code only once on a multithreading environment?

The following code block, performs loading of an object in C#.

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

My intention is to run this block only once, and hence loading the Model only once. Nevertheless, this code block runs twice from 2 different threads.

How can I make sure that this block runs only once? (on multiple threads).

like image 955
KayzerSoze Avatar asked Oct 26 '12 14:10

KayzerSoze


6 Answers

Use the 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;
}
like image 84
dtb Avatar answered Oct 05 '22 10:10

dtb


Simplest would be to add

[MethodImpl(MethodImplOptions.Synchronized)]
public override MyObject Load()
{
   //snip
}

but be aware this puts a lock on the entire object, not just the method. Not really great practice.

http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions.aspx

Synchronized

Specifies that the method can be executed by only one thread at a time. Static methods lock on the type, whereas instance methods lock on the instance. Only one thread can execute in any of the instance functions, and only one thread can execute in any of a class's static functions.

like image 41
GazTheDestroyer Avatar answered Oct 05 '22 11:10

GazTheDestroyer


I are trying to implement singleton pattern. But your version is not thread safe. Read more here: http://www.dofactory.com/Patterns/PatternSingleton.aspx. Try to use this implementation:

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;
            }
        }
    }
}
like image 41
Artem Vyshniakov Avatar answered Oct 05 '22 11:10

Artem Vyshniakov


If you want to write thread safe code and make sure that the block runs only once, you can write like this:

private System.Object lockThis = new System.Object(); 
public override MyObject Load()
{
    lock (lockThis) {
        if (!IsModelLoaded)
        {
            Model = MyService.LoadMyObject(Model);
            IsModelLoaded = true;
        }
    }
    return Model;
}
like image 35
Roozbeh Zabihollahi Avatar answered Oct 05 '22 11:10

Roozbeh Zabihollahi


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

After calling myCodeBlock() once it will be rewritten by method that does nothing. You still need to make sure this metod is called safely - use lock or whatever.

like image 22
Anri Avatar answered Oct 05 '22 12:10

Anri


You can use lock Statement (C# Reference)

like image 35
atredis Avatar answered Oct 05 '22 12:10

atredis