Example #1
0
 /// <summary>
 /// Assert to find possible deadlocks in code that uses async/await
 /// Throws an exception of type <see cref="ConcurrencyException"/> if any errors are found.
 /// </summary>
 /// <exception cref="ConcurrencyException"></exception>
 /// <param name="action">Delegate to execute</param>
 /// <param name="shouldEndBeforeMs">Maximum time in which the code should execute, this is used to determine deadlocks.</param>
 public static void AssertAsyncDeadlocksOnly(Action action, int shouldEndBeforeMs = 2000)
 {
     try
     {
         var cts = new CancellationTokenSource(shouldEndBeforeMs);
         ConcurrentRunner.Start(new[] { action }, 1, cts.Token);
     }
     catch (OperationCanceledException)
     {
         throw new ConcurrencyException("Possible deadlock detected. Make sure that you do not use .Wait(), .WaitAny(), .WaitAll(), .GetAwaiter().GetResult() or .Result on async methods.");
     }
 }
Example #2
0
        /// <summary>
        /// Will run the concurrency checker and will output a report if there were any errors.
        /// It will throw an exception of type <see cref="ConcurrencyException"/> if any errors are found.
        /// </summary>
        /// <param name="numberOfConcurrentThreads">Number of concurrent threads to run. The higher the number the more likely a problem will be found.</param>
        /// <param name="actions">Actions to execute concurrently</param>
        /// <example>ConcurrencyChecker.AssertRun(5, new Action(() => instance.ChangeNameTo("Jane")), new Action(() => instance.ChangeNameTo("Peter")))</example>
        /// <returns>Report if failed or null if successful</returns>
        public string Run(int numberOfConcurrentThreads, params Action[] actions)
        {
            if (numberOfConcurrentThreads < actions.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(numberOfConcurrentThreads), "Number of concurrent threads are less than the number of actions to execute.");
            }

            _cts = new CancellationTokenSource(5000);

            try
            {
                InitializeMembersToMonitor();
            }
            catch (OperationCanceledException)
            {
                return("Initialization failed. This normally happens is you are using a mock framework such as Moq. Please exclude the mock namespace (NSubstitute and Moq is supported out of the box).");
            }

            _cts = new CancellationTokenSource();

            Start(true);

            actions.First()();

            Stop();

            _cts = new CancellationTokenSource(MaxExecutionTimeMs);

            try
            {
                Start();

                ConcurrentRunner.Start(actions, numberOfConcurrentThreads, _cts.Token);

                Stop();

                return(GetReport());
            }
            catch (OperationCanceledException)
            {
                return("Possible deadlock detected. Make sure that you do not use .Wait() or .Result on async methods.");
            }
        }