読者です 読者をやめる 読者になる 読者になる

「Androidは電気羊の夢を見るか」を読みたい管理者のブログ

仕事などでの色々な発見を記事にしてます。不定期更新。

スレッド処理博物館

今回は過去の記事の焼きまわしです。

どうしても納得できない表示があったので。

元々
スレッド処理博物館(主にUIスレッドとの分離を中心に) - 「Androidは電気羊の夢を見るか」を読みたい管理者のブログ


参考にした
.NET開発における非同期処理の基礎と歴史 − @IT


using System;
using System.Windows.Forms;
using System.Threading;
namespace ThreadMusiam
{
    delegate void UIDelegate();

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        /// <summary>
        /// UIスレッドで時間のかかる処理
        /// UIがフリーズする例
        /// </summary>
        private void button1_Click(object sender, EventArgs e)
        {
            ((Button)sender).Enabled = false;
            Thread.Sleep(3000);
            ((Button)sender).Enabled = true;
        }
        /// <summary>
        /// .Net黎明期の頃の非同期処理。
        /// UIコントロールの操作にはInvokeメソッドを呼び出さなければならなかった。
        /// </summary>
        private void button2_Click(object sender, EventArgs e)
        {
            ((Button)sender).Enabled = false;
            var thread = new Thread(() =>
            {
                Thread.Sleep(1000);

                this.Invoke(new UIDelegate(() =>//スレッド上からではUIのコントロールに直接アクセスすることは禁止されているためInvokeメソッドを使う。以下同様。
                    {
                        ((Button)sender).Enabled = true;

                    }));
            });
            thread.Start();
        }
        /// <summary>
        /// Threadオブジェクトの生成には処理の負担が重いということで考え出されたのが
        /// スレッドプールという考え方。
        /// あらかじめプールに水が溜められているようにスレッドが溜められているプールが
        /// 存在してそこにあるスレッドを使おうという考え方なんだ。
        /// </summary>
        private void button3_Click(object sender, EventArgs e)
        {
            ((Button)sender).Enabled = false;
            ThreadPool.QueueUserWorkItem(_ =>
                {
                    Thread.Sleep(3000);

                    this.Invoke(new UIDelegate(() =>
                    {
                        ((Button)sender).Enabled = true;

                    }));
                },null);
        }
        /// <summary>
        /// .Net3.5だとここまで対応している。
        /// 最近はあまり使われていないらしい。
        /// 戻り値が習得できる。
        /// </summary>
        private void button4_Click(object sender, EventArgs e)
        {
            ((Button)sender).Enabled = false;
            var method = new Func<double>(() =>
            {
                Thread.Sleep(3000);
                return Math.PI;
            });
            method.BeginInvoke(ar =>//BeginInvoke()はDelegateの関数である。BeginInvoke()の引数はスレッドの処理が終わった時に呼ばれる関数である。
                {
                    var result = method.EndInvoke(ar);//EndInvokeはスレッドの終了を待機し、戻り値を取得する事が出来る。ここを通る時点ではスレッドは既に終了しているためこの記述は戻り値の取得のみを目的としている。

                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.ShowDialog();

                    this.Invoke(new UIDelegate(() =>
                        {

                            //MessageBox.Show("終了しました");
                            ((Button)sender).Enabled = true;

                        }));
                },null);
        }
        /// <summary>
        /// Task.Factory.StartNewメソッドは、Taskの生成と実行を一挙に行うものだ。
        /// </summary>
        private void button5_Click(object sender, EventArgs e)
        {
            button5.Enabled = false;
            Task.Factory.StartNew(() => Thread.Sleep(3000))
            .ContinueWith(_ =>
            {
                button5.Enabled = true;
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
        /// <summary>
        /// asyncキーワードを付加するだけでUIスレッドとは別のスレッドで処理してくれるようになったんだ。
        /// </summary>
        private async void button6_Click(object sender, EventArgs e)
        {
            button6.Enabled = false;
            await Task.Run(() => Thread.Sleep(3000));
            button6.Enabled = true;
        }
  }
}