非同期で複数処理を実行し、対話式で制御する

# 概要
開始と終了命令をコンソールからいつでも入力可能かつ、開始時には非同期で複数の処理を実行可能で、任意のタイミングでいつでも処理を停止できるようなプログラムを組んでみた

こんなイメージ
![スクリーンショット 2015-04-29 20.08.13.png](https://qiita-image-store.s3.amazonaws.com/0/65312/ba5fb35a-75f1-c8c8-5100-dd7bec10e5e5.png)


# 非同期でタスクを実行
```csharp
// ABCを非同期で同時実行
Task.Run(ActionA);
Task.Run(ActionB);
Task.Run(ActionC);
```

# タスクを取り消す
タスクを取り消すにはMSの[タスクとその子を取り消す](https://msdn.microsoft.com/ja-jp/library/dd537607%28v=vs.110%29.aspx)にある通りCancellationTokenSourceを利用すると実装できるみたい。

```csharp
// キャンセルトークンの取得
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

// トークン付きで実行
Task.Run(()=>ActionA(token), token);

// 停止命令を送る
tokenSource.Cancel()

// ActionAに停止処理を追加
static void ActionA(CancellationToken token)
   {
      while(true){
         // メインロジック
         Thread.sleep(1000);

         // キャンセル時の処理
         if (token.IsCancellationRequested) {
              break;
         } 
      }
   } 

```

# 実際のコード
```csharp
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncPractice
{
    class Program
    {
        static void Main(string[] args)
        {
            // Task停止用のトークン発行
            var cancelTokenSource = new CancellationTokenSource();
            CancellationToken cToken = cancelTokenSource.Token;

            while (true)
            {

                // 入力受付
                Console.Write("> ");
                string msg = Console.ReadLine();

                // 処理開始
                if (msg == "stat" || msg == "s")
                {
                    Console.WriteLine("Ascnc Practice START");

                    // 非同期処理をそれぞれ実行
                    Task.Run(() => sleep("processA", 3000, cToken), cToken);
                    Task.Run(() => sleep("processB", 5000, cToken), cToken);
                    Task.Run(() => sleep("processC", 1000, cToken), cToken);

                    continue;
                }

                // 処理終了
                if (msg == "stop")
                {
                    // 非同期処理の終了
                    cancelTokenSource.Cancel();
                    Console.WriteLine("Stop!");
                }

                // アプリ終了
                if (msg == "quit" || msg == "q")
                {
                    break;
                }

            }
            // 非同期処理の終了
            cancelTokenSource.Cancel();
            cancelTokenSource.Dispose();
        }

        public static void sleep(string tag, int millseconds, CancellationToken token)
        {
            int ct = 0;
            while (true)
            {
                Thread.Sleep(millseconds);
                ct += 1;
                Console.WriteLine("[{0}] {1}回目のループ完了", tag, ct.ToString());

                // 中止リクエストあれば停止
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("[{0}] 処理停止", tag);
                    break;
                }
            }
        }

    }
}


```

# 実行してみた
![スクリーンショット 2015-04-29 20.31.46.png](https://qiita-image-store.s3.amazonaws.com/0/65312/417acc6a-8be7-403a-1e7d-a52c3abb76d7.png)

![スクリーンショット 2015-04-29 20.32.18.png](https://qiita-image-store.s3.amazonaws.com/0/65312/8e5e5e64-531c-ce2f-807a-3a8ef659270a.png)




# 実現できていなこと
・中断と再開の処理が上記コードでは実現できていない。
・CancellationTokenSourceは使い捨て推奨だが、このコードでは使い回している。disposeした後にtokenを再利用すると破棄されているためエラーが発生する。

# 対話式アプリではライフサイクル設計が必要
アプリ起動 → 処理起動 → 一時停止 → 再開 → 処理停止 → アプリ終了
のように対話式でステータスを変更するアプリを開発するには、ライフサイクル設計をする必要がある。作っていて「処理停止」と「アプリ停止」が異なる概念と気づきました。