サイトアイコン CAD日記

マルチスレッドプログラミング(C#編)

マルチスレッドプログラミング(C++編)
マルチスレッドプログラミング(VB.net編)
に続く第三弾はC#編。

前の2回は昔ながらのThreadクラス(System.Threading名前空間)していたが、async(エイシンク)/await(アウェイト)という最新の技術をC#で実現してみた。いや、実際のところはおいらが書いたわけではない。とあるプログラム博士にVB.netで書いてもらったのを、C#に変換してちょいと手を入れてみただけ。この程度の改修であっても、アラフィフプログラマのおいらにとっては充実感のある活動となった。こういうきっかけがあると、今後自分でもC#やVBのプログラムをいじってみる気になるかもしれない。async/awaitは最新技術なだけあって、VisualStudio2012以降じゃないと使えないってことだったので、前2回のVS2010ではなく最新のVS2017を使ってみた。こういう最新の開発環境に触れられたのも大きいな。

画面設計とソースコードは以下の通りで、Visual Studio 2017 C#のプロジェクト一式はこちら。

Imports System.Threading
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace ThreadTestCSAsync
{
  public partial class Form1 : Form
  {
    private int count = 0;
    private bool exec = false;
    private CancellationTokenSource canceled;
    private TaskCompletionSource<bool> waitForStop;
    protected override void WndProc(ref Message m)  // 実行中はクローズボタンを無効にする
    {
      const int WM_SYSCOMMAND = 0x112;
      const long SC_CLOSE = 0xF060L;
      if (exec == true && m.Msg == WM_SYSCOMMAND && (m.WParam.ToInt64() & 0xFFF0L) == SC_CLOSE)
        return;
      base.WndProc(ref m);
    }
    public Form1()
    {
      InitializeComponent();
      MaximizeBox = false;
    }
    private async void button1_Click(object sender, EventArgs e)
    {
      if (canceled != null)
        return;
      ClearCount();
      button1.Enabled = false;
      button2.Enabled = true;
      exec = true;
      canceled = new CancellationTokenSource();
      try
      {
        int i;
        for (i = 1; i <= 10; i++)
        {
          IncrementCount();
          await Task.Run(() =>
          {
            Thread.Sleep(3000);
          });
          if (waitForStop != null)
            await waitForStop.Task;
          canceled.Token.ThrowIfCancellationRequested();
        }
        MessageBox.Show("正常終了", "情報", MessageBoxButtons.OK, MessageBoxIcon.Information);
      }
      catch (OperationCanceledException)
      {
        ClearCount();
        MessageBox.Show("中止", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      catch (Exception)
      {
        ClearCount();
        MessageBox.Show("異常終了", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        canceled = null;
        button1.Enabled = true;
        button2.Enabled = false;
        exec = false;
      }
    }
    private void button2_Click(object sender, EventArgs e)
    {
      if (waitForStop != null)
        return;
      waitForStop = new TaskCompletionSource<bool>();
      try
      {
        if (MessageBox.Show("中止しますか?", "質問", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
        {
          if (canceled != null)
          {
            canceled.Cancel();
            button2.Enabled = false;
          }
        }
      }
      finally
      {
        waitForStop.SetResult(true);
        waitForStop = null;
      }
    }
    private void ClearCount()
    {
      count = 0;
      UpdateText();
    }
    private void IncrementCount()
    {
      count = count + 1;
      UpdateText();
    }
    private void UpdateText()
    {
      label1.Text = string.Format("時間のかかる処理を実行中。{0}/10", count);
    }
  }
}

プログラムってのはホントおもしろいよなぁ。最近は仕事でプログラムをやらなくなったから、プログラムをつくることの喜びを忘れていた。こうやって休日に家でプログラムをやっているというのは仕事というわけではなく、あくまで趣味。少なくとも今の仕事に生かすつもりはなくて、純粋に自分の楽しみ。もしかしたら、今の仕事と全く別で役に立つかもしれないという色気もあるし、さらに言えばこの記事を読んで助かったという人間が1人でもいればよい。ググれば何でも出てくる時代でも、こういう要求はネット上にピンポイントで転がっていないわけだから誰かの役に立つことと思う。そうやって少しでもアクセス件数が増えて、Adsenseの収益が上がることももちろん期待している。

モバイルバージョンを終了