Avatar of Russ Suter
Russ Suter

asked on 

Need help with awaitable tasks

I'm used to doing things the old-fashioned way with BackgroundWorker objects and multiple threads. I'm trying to figure out how to use the (seemingly better) awaitable task method of doing things. I created a UserControl with 3 progress bars. The UserControl code looks like this:
	public partial class MultiTaskThingy : UserControl
	{
		public MultiTaskThingy()
		{
			InitializeComponent();
		}

		public async Task<AsyncStatus> RunMultipleTasks(AsyncProgress<AsyncStatus> progress, CancellationToken cToken)
		{
			AsyncThingy thingy = new AsyncThingy();
			AsyncStatus overallStatus = new AsyncStatus();
			var localProgress = new AsyncProgress<AsyncStatus>(ReportProgress);
			List<Task<AsyncStatus>> taskList = new List<Task<AsyncStatus>>() { thingy.PseudoTask("1", localProgress, cToken), thingy.PseudoTask("2", localProgress, cToken), thingy.PseudoTask("3", localProgress, cToken) };
			try
			{
				await Task.WhenAll(taskList);
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.Print(ex.Message);
			}
			return overallStatus;
		}

		void ReportProgress(AsyncStatus value)
		{
			switch (value.Context)
			{
				case "1":
					progressBar1.Invoke(pb => { pb.Value = value.PercentComplete; });
					break;
				case "2":
					progressBar2.Invoke(pb => { pb.Value = value.PercentComplete; });
					break;
				case "3":
					progressBar3.Invoke(pb => { pb.Value = value.PercentComplete; });
					break;
				default:
					throw new ArgumentOutOfRangeException($"Context {value.Context} is not valid");
			}
		}
	}

Open in new window

I then have that UserControl on a Windows Form with a single button that kicks things off. The button code is:
		private async void buttonDoManyThings_Click(object sender, EventArgs e)
		{
			_cts = new CancellationTokenSource();
			var progressIndicator = new AsyncProgress<AsyncStatus>(ReportProgress);
			await Task.Run(() => multiTaskThingy.RunMultipleTasks(progressIndicator, _cts.Token));
			_cts.Dispose();
			_cts = null;
		}

Open in new window

All 3 tasks run and the calling UI thread isn't blocked. However, the tasks run sequentially rather than concurrently. This isn't what I expected. Can anyone tell me what I'm doing wrong?

FYI, The AsyncThingy class contains the PseudoTask method which is nothing more than a loop counter with an arbitrary length between 5 and 15 seconds. It just reports a progress back to the caller.
.NET ProgrammingC#

Avatar of undefined
Last Comment
kaufmed

8/22/2022 - Mon