2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

usingの後にawaitを呼んだ場合に、対応するDisposeはどのスレッドで呼ばれるか

Posted at

参考

こちらの記事を参考にさせていただきました

目的

usingの後にawaitを呼んだ場合に、対応するDisposeはどのスレッドで呼ばれるのか確認しました

結果

  • ConfigureAwait(false)をつけないでawaitした場合、usingを呼んだスレッドに戻ってからDisposeが呼ばれた
  • ConfigureAwait(false)をつけてawaitした場合、usingを呼んだスレッドに戻らずにDisposeが呼ばれた
  • using宣言と、スコープを指定するusing、usingと同等のtry&finallyの置き換えで同様の動作となった

確認用コード

MainWindow.xaml.cs
using System.Diagnostics;
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static class DebugLogger
        {
            public static void LogDebug(string message)
            {
                int threadId = Thread.CurrentThread.ManagedThreadId;
                Debug.WriteLine($"[Thread {threadId}] {message}");
            }
        }

        public class MyData : IDisposable
        {
            public string Data { get; set; } = "Initial Data";

            public MyData()
            {
                DebugLogger.LogDebug("MyData Constructor Called");
            }

            public void Dispose()
            {
                DebugLogger.LogDebug("MyData Disposed");
            }
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        public async Task ProcessDataAsync(MyData data)
        {
            await Task.Run(() =>
            {
                DebugLogger.LogDebug("Processing data...");
                Thread.Sleep(1000);
                data.Data = "Processed Data";
                DebugLogger.LogDebug($"Data updated to: {data.Data}");
            });
        }

        private async void Button1_Click(object sender, RoutedEventArgs e)
        {
            DebugLogger.LogDebug("//-----------------------");
            DebugLogger.LogDebug("Button1_Click Starting...");
            using var myData = new MyData();
            await ProcessDataAsync(myData);
            DebugLogger.LogDebug("Button1_Click Finished.");
        }

        private async void Button2_Click(object sender, RoutedEventArgs e)
        {
            DebugLogger.LogDebug("//-----------------------");
            DebugLogger.LogDebug("Button2_Click Starting...");
            using var myData = new MyData();
            DebugLogger.LogDebug("ProcessDataAsync Starting...");
            await ProcessDataAsync(myData).ConfigureAwait(false);
            DebugLogger.LogDebug("Button2_Click Finished.");
        }

        private async void Button3_Click(object sender, RoutedEventArgs e)
        {
            DebugLogger.LogDebug("//-----------------------");
            DebugLogger.LogDebug("Button3_Click Starting...");
            using (var myData = new MyData())
            {
                await ProcessDataAsync(myData);
            }
            DebugLogger.LogDebug("Button3_Click Finished.");
        }

        private async void Button4_Click(object sender, RoutedEventArgs e)
        {
            DebugLogger.LogDebug("//-----------------------");
            DebugLogger.LogDebug("Button4_Click Starting...");
            using (var myData = new MyData())
            {
                await ProcessDataAsync(myData).ConfigureAwait(false);
            }
            DebugLogger.LogDebug("Button4_Click Finished.");
        }

        private async void Button5_Click(object sender, RoutedEventArgs e)
        {
            DebugLogger.LogDebug("//-----------------------");
            DebugLogger.LogDebug("Button5_Click Starting...");
            MyData? myData = null;
            try
            {
                myData = new MyData();
                DebugLogger.LogDebug("ProcessDataAsync Starting...");
                await ProcessDataAsync(myData);
                DebugLogger.LogDebug("ProcessDataAsync Finished.");

            }
            catch (Exception ex)
            {
                DebugLogger.LogDebug($"An error occurred: {ex.Message}");
            }
            finally
            {
                if (myData != null)
                {
                    myData.Dispose();
                    DebugLogger.LogDebug("MyData disposed in finally block.");
                }
                DebugLogger.LogDebug("Button5_Click Finished.");
            }
        }

        private async void Button6_Click(object sender, RoutedEventArgs e)
        {
            DebugLogger.LogDebug("//-----------------------");
            DebugLogger.LogDebug("Button6_Click Starting...");
            MyData? myData = null;
            try
            {
                myData = new MyData();
                DebugLogger.LogDebug("ProcessDataAsync Starting...");
                await ProcessDataAsync(myData).ConfigureAwait(false);
                DebugLogger.LogDebug("ProcessDataAsync Finished.");
            }
            catch (Exception ex)
            {
                DebugLogger.LogDebug($"An error occurred: {ex.Message}");
            }
            finally
            {
                if (myData != null)
                {
                    myData.Dispose();
                    DebugLogger.LogDebug("MyData disposed in finally block.");
                }
                DebugLogger.LogDebug("Button6_Click Finished.");
            }
        }
    }
}

出力結果

[Thread 1] //-----------------------
[Thread 1] Button1_Click Starting...
[Thread 1] MyData Constructor Called
[Thread 15] Processing data...
[Thread 15] Data updated to: Processed Data
[Thread 1] Button1_Click Finished.
[Thread 1] MyData Disposed
[Thread 1] //-----------------------
[Thread 1] Button2_Click Starting...
[Thread 1] MyData Constructor Called
[Thread 1] ProcessDataAsync Starting...
[Thread 3] Processing data...
[Thread 3] Data updated to: Processed Data
[Thread 3] Button2_Click Finished.
[Thread 3] MyData Disposed
[Thread 1] //-----------------------
[Thread 1] Button3_Click Starting...
[Thread 1] MyData Constructor Called
[Thread 3] Processing data...
[Thread 3] Data updated to: Processed Data
[Thread 1] MyData Disposed
[Thread 1] Button3_Click Finished.
[Thread 1] //-----------------------
[Thread 1] Button4_Click Starting...
[Thread 1] MyData Constructor Called
[Thread 3] Processing data...
[Thread 3] Data updated to: Processed Data
[Thread 3] MyData Disposed
[Thread 3] Button4_Click Finished.
[Thread 1] //-----------------------
[Thread 1] Button5_Click Starting...
[Thread 1] MyData Constructor Called
[Thread 1] ProcessDataAsync Starting...
[Thread 3] Processing data...
[Thread 3] Data updated to: Processed Data
[Thread 1] ProcessDataAsync Finished.
[Thread 1] MyData Disposed
[Thread 1] MyData disposed in finally block.
[Thread 1] Button5_Click Finished.
[Thread 1] //-----------------------
[Thread 1] Button6_Click Starting...
[Thread 1] MyData Constructor Called
[Thread 1] ProcessDataAsync Starting...
[Thread 15] Processing data...
[Thread 15] Data updated to: Processed Data
[Thread 15] ProcessDataAsync Finished.
[Thread 15] MyData Disposed
[Thread 15] MyData disposed in finally block.
[Thread 15] Button6_Click Finished.
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?