Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Increase a value type from multiple async methods (i.e. threads) in C#

I need to increase a counter from multiple threads (async methods) in C#.

  • I cannot pass a ref parameter because it's an async method
  • I cannot just update the value (or lock on it) because it's a value type
  • I cannot use Interlocked because I can't put a ref to the counter in the async method

So the only thing I'm coming up with is to make something silly like a List<int> and put my int in there so threads can lock on the List and update the value.

I'm hoping that's a known use case and there's a more elegant way of doing it?

Here's a small example, never mind small syntax issues:

public void DoStuff()
{
    int counter;
    var tasks = new List<Task>()
    for(int i = 0; i < 10; i++)
    {
        tasks.Add(AsyncMethod(<SOMETHING>));
    }
    Task.WaitAll(tasks);
    Console.WriteLine("Total: {0}", counter);
 }

 public async Task AsyncMethod(<SOMETHING>)
 {
     // Lock if needed by <SOMETHING>
     <SOMETHING>+=20;
 }

Do I need to create a class with an int field, or does C# provide something off-the-box? I'm not stuck on this, just trying to learn in hindsight if there was a better way. Thanks!

FOR FUTURE VISITORS: The consensus seems to be to create a custom class such as class IntHolder { public int Value {get;set;}} that can be passed by reference and locked on (or use Interlocked on)

Thanks a lot all!

like image 557
Miquel Avatar asked Sep 28 '15 22:09

Miquel


1 Answers

You can using lock on any object, not just the object that you want to use.

For example:

object locking_object = new object();

This creates an object that will be used only for locking.

And then later, when you want to increment the value:

lock(locking_object)
{
    integer++;
}

Update based on the comments:

Create a class to hold the integer value like this:

class IntHolder
{
    public int Value;
}

You can use the Interlocked class to do something like this:

Interlocked.Increment(ref int_holder.Value);

Where int_holder is the name of the variable of type IntHolder that you pass to your method.

like image 191
Yacoub Massad Avatar answered Sep 20 '22 03:09

Yacoub Massad