C# Async Lock

Sep25.17 12AM

Something which you shouldn’t be doing very often (or ever) is placing locks around chunks of asynchronous code. You’re almost always slowing down your code, and there has to be a better way to do it. Anyway, if you do try it, C# will give you a compile error along the lines of: ‘cannot await in the body of a lock statement’. This all makes sense, because locks are tied to a thread. If you are using the parallel task library, there is really no guarantee that your code is going to pick back up on the same thread where it originally left off. You can run into problems like this if you try to use a class like “ReadWriteLockSlim”, which doesn’t give compile warning about awaiting within the critical section, but will happily deadlock your code. So here is a solution to all your fears. Luckily SemaphoreSlim has async support.
This is a helper class which just makes a generic disposable for some coding sugar:
raw
    /// <summary>
    /// A class which can be disposed.
    /// </summary>
    public class Disposable : IDisposable
    {
        /// <summary>
        /// The action to perform on dispose.
        /// </summary>
        private readonly Action onDispose;

        /// <summary>
        /// Initializes a new dispoable.
        /// </summary>
        /// <param name="onDispose">The action to perform.</param>
        private Disposable(Action onDispose)
        {
            this.onDispose = onDispose;
        }

        /// <summary>
        /// Creates a disposable class.
        /// </summary>
        /// <param name="onDispose">The dispose action.</param>
        /// <returns>A disposable.</returns>
        public static IDisposable Create(Action onDispose)
        {
            return new Disposable(onDispose);
        }

        /// <summary>
        /// Dispose.
        /// </summary>
        public void Dispose()
        {
            onDispose();
        }
    }
                            
                        
This is a dummy object which needs a lock:
raw
public class LockableObject
    {
        private readonly SemaphoreSlim asyncLock = new SemaphoreSlim(1);

        /// <summary>
        /// Gets a lock on this object.
        /// </summary>
        /// <param name="token">The token.</param>
        /// <returns>A disposable which release the lock.</returns>
        public Task<IDisposable> GetLock(CancellationToken token)
        {
            return this.asyncLock.WaitAsync(token).ContinueWith(result =>
            {
                if (result.IsCompleted && !result.IsFaulted && !result.IsFaulted)
                {
                    return Disposable.Create(() => asyncLock.Release());
                }

                throw result.Exception?.InnerExceptions.FirstOrDefault() ?? result.Exception ??
                      new Exception("Failed to aquire the lock for an unknown reason.");
            });
        }
    }
                            
                        
Here is a little demo test program:
raw
class Program
    {
        static void Main(string[] args)
        {
            // This wont work...
            ////var obj = new object();
            ////
            ////lock (obj)
            ////{
            ////    await TestLock();
            ////}

            TestLock().GetAwaiter().GetResult();
        }

        /// <summary>
        /// Test to see if this lock works
        /// </summary>
        /// <returns>An async task.</returns>
        public static async Task TestLock()
        {
            const int number = 10000;
            var someObject = new LockableObject();

            var parallelSum = 0L;

            using (var barrier = new ManualResetEventSlim(false))
            {

                var tasks = Enumerable.Range(0, number).Select(i => Task.Run(async () =>
                {
                    // Queue up everything behind this barrier so things try to do this all at once.
                    barrier.Wait();

                    using (await someObject.GetLock(CancellationToken.None)) // Comment out this line to make it fail
                    {
                        // Critical Section
                        var t = parallelSum;
                        parallelSum = t + 1;
                    }
                }));

                barrier.Set();

                await Task.WhenAll(tasks);

            }

            if (parallelSum != number)
            {
                throw new Exception($"The counter is wrong. Expected {number}, but got {parallelSum}");
            }
        }
    }
                            
                        
A major caveat here is that this lock is not at all recursive/re-entrant. If you try to call it within the same call stack, you will most certainly deadlock. Other than that, happy locking.



Some messy C# code.

Mar09.17 07AM

Ever been asked FizzBuzz in a programming interview, and thought to yourself, what could I do here that would really throw them off? Well, this. Do this.
raw
private static void FizzBuzz1()
{              
	// Declare all of our variables right here at the top.
	int i, i2;
	string buff;
	Action<string> fb = null;
	goto assignVars;
	loop:
	{
		if (0 == i2 % 3)
		goto dofizz;
		if (0 == i2 % 5)
		goto dobuzz;
		goto donumber;
	}
	endoftheloop:
	if (i --> 0 && (i2 = 100 - i) > 0)
	goto loop;
	goto end;
	dofizz:
	buff += "fizz";
	if (0 == i2 % 5)
	goto dobuzz;
	goto writer;
	dobuzz:
	buff += "buzz";
	goto writer;
	donumber:
	buff += i2;
	writer:
	fb(buff + Environment.NewLine);
	goto justBuff;
	// Do this safely at the end of the function.
	assignVars:
	i = 100;
	fb = Console.Write;
	justBuff:
	buff = string.Empty;
	goto endoftheloop;
	end: ;
}
                            
                        
Nobody can be tooooo mad, since it really is a completely working fizzbuzz. Some may question who taught you that goto works in c#, and why you dont seem to know how to use a for-loop. Some may even question why you assigned Console.Write to an action, or why you didn't just use Console.WriteLine. All good questions. Seems like you would have a lot to talk about during your interview.
Theres nothing like a single method chain which does all of Fizz Buzz. So here's some awesome.
raw
private static void FizzBuzz2()
{
  Console.WriteLine(
    string.Join(
      Environment.NewLine,
      Enumerable.Range(1, 100)
        .Select(
          i =>
            string.Join(
              string.Empty,
              i % 3 == 0 ? "fizz" : null,
              i % 5 == 0 ? "buzz" : null,
              !(i % 5 == 0 || i % 3 == 0) ? $"{i}" : null))));
}
                            
                        



Here is a fun coding problem. The idea is simple. g()("al") outputs "goal". g()()("al") outputs "gooal". And so on. So here is what it comes down to. A call to g(), needs to return either a function, or a string. Sounds simple enough. In C# you can get it done with heavy use of the 'dynamic' type, and a delegate.
raw
namespace Goal
{
    using System;
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(G()("al"));
            Console.WriteLine(G()()("al"));
            Console.WriteLine(G()()()("al"));
            Console.WriteLine(G()()()()("al"));
            Console.WriteLine(G()()()()()("al"));
            Console.ReadLine();
        }
        delegate dynamic g(string a = "o");
        static dynamic G(string o = "o", string curr = "g")
        {
            return o == "al" ? (dynamic)curr + o : new g((a) => G(a, curr + o));
        }
    }
}
                            
                        
There we have it! The output will be something like:
  • goal
  • gooal
  • goooal
  • gooooal
  • goooooal



© 2017 - Peter Sulucz | disclaimer

log in