質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

2回答

2567閲覧

C# 一定時間ごとの処理

senkei_river

総合スコア15

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

0クリップ

投稿2020/05/12 23:20

編集2020/05/13 11:21

C#で一定時間ごとに処理させようと思ってます。
大まかな処理の流れは以下です。

処理の流れ

処理1→処理2→処理3→[1秒]→処理1→処理2→処理3→[1秒]→処理1→処理2→処理3→[3秒]→処理1→処理2→処理3→[1秒]→・・・

「処理1→処理2→処理3→[1秒]」が一つの処理の単位で、これが3回終われば3秒待つというような処理を書こうとしています。

上記を実現するのに、DispatcherTimerを二つ使って処理を書いたのですが、[3秒]にあたる待ち時間が、初めに実行している処理1からの経過時間となってしまい、処理3終了から3秒となりません。どのように修正すればよいかご教授ください。

using System; using System.Windows; using System.Windows.Threading; namespace timerSamplePrj { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { DispatcherTimer timer= new DispatcherTimer(); DispatcherTimer timer2 = new DispatcherTimer(); string[] files = { "a", "b", "c" }; int fileIter = 0; public MainWindow() { InitializeComponent(); timer.Interval = TimeSpan.FromMilliseconds(1000); timer.Tick += send; timer2.Interval = TimeSpan.FromMilliseconds(3000); timer2.Tick += exec; } private void send(object sender, EventArgs e) { Console.WriteLine("send関数で" + files[fileIter++] + "を実行中"); if (fileIter == files.Length) { timer.Stop(); fileIter = 0; } } private void exec(object sender, EventArgs e) { Console.WriteLine("send中"); textBox.Text = "実行中"; timer.Start(); } private void button_Click(object sender, RoutedEventArgs e) { timer2.Start(); } private void button1_Click(object sender, RoutedEventArgs e) { timer2.Stop(); timer.Stop(); } } }

[補足]
皆様、迅速なご回答ありがとうございます。適切な説明になっていない点もあり、改めて実現したい処理の流れを以下に記載させていただきます。

処理の流れ

func関数実行[1秒]→func関数実行→[1秒]→func関数実行→[3秒]→func関数実行→[1秒]→・・・

「func関数実行→[1秒]」が一つの処理の単位で、これがn回終われば3秒待つというような処理の流れです。

上記を実現するのに、以下ソースコードを書きました。ここで改めて質問させていただきたいのですが、timerのintervalプロパティを変更する、というのは適切なのでしょうか(intervalプロパティを変更し、待ち時間を変更させるというのは使い方が違う気がしてます)。
また、GUI上に配置するボタン押下で繰り返し実行処理を終了させたく、Zuishin様から頂いたTask.Delay()関数を使ったwhile文ループでは一度forループに入ると3回分の処理が実行されてしまうと思っており、途中で処理を終了させるようにもしたいです。

using System; using System.Windows; using System.Windows.Threading; namespace timerSamplePrj { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { DispatcherTimer timer= new DispatcherTimer(); string[] files = { "a", "b", "c" }; int fileIter = 0; public MainWindow() { InitializeComponent(); timer.Interval = TimeSpan.FromMilliseconds(0); timer.Tick += func; } private void func(object sender, EventArgs e) { Console.WriteLine("func関数で" + files[fileIter++] + "を実行中"); if (fileIter == files.Length) { fileIter = 0; timer.Interval = TimeSpan.FromMilliseconds(3000); } else { timer.Interval = TimeSpan.FromMilliseconds(1000); } } private void button_Click(object sender, RoutedEventArgs e) { Console.WriteLine("exec開始"); timer.Start(); } private void button1_Click(object sender, RoutedEventArgs e) { Console.WriteLine("exec終了"); fileIter = 0; timer.Stop(); timer.Interval = TimeSpan.FromMilliseconds(0); } } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/05/12 23:35 編集

このような複雑な時間間隔の場合は、タイマーを使うよりも Reactive Extensions や非同期処理を使うほうが簡潔に書けます。 while (条件) { for (int i = 0; i < 3; i++) { 処理1 処理2 処理3 await Task.Delay(1000); } await Task.Delay(2000); }
Zuishin

2020/05/12 23:50

なお、別スレッドから他のコントロールにアクセスすると例外が発生するので、その場合は次のように UI スレッドに処理を戻してください。 Dispatcher.Invoke(() => { 処理1 処理2 処理3 )); await Task.Delay(1000);
Zuishin

2020/05/13 06:18

御託はいいから自分の望み通りのものを作れという意味ですか?
senkei_river

2020/05/13 06:37

そのような意図ではございません。 y_waiwaiのご回答にもあるように、ソースコードと処理の対応もついておらず、おかしな説明となっていた点を修正した次第です。 不快にさせてしまったなら申し訳ございませんでした。
Zuishin

2020/05/13 06:43

すでに付いている回答のどこが不満なのかをそれぞれの回答にコメントとして書いてください。 何の反応も無ければ回答の修正のしようもないでしょう。 不満がないのであればベストアンサーを選んでください。
senkei_river

2020/05/13 06:48

補足の方法についてご指摘ありがとうございます。 以後気を付けます。。。
guest

回答2

0

ベストアンサー

こんな構造体を作ってタスクをリスト化すればよいと思います。

C#

1struct task 2{ 3 public string Name; 4 public Action<task> Proc; 5 public int Interval; 6}

で、こんな感じに

C#

1using System; 2using System.Collections.Generic; 3using System.Diagnostics; 4using System.Windows; 5using System.Windows.Threading; 6 7namespace WpfApp1 8{ 9 struct task 10 { 11 public string Name; 12 public Action<task> Proc; 13 public int Interval; 14 } 15 16 public partial class MainWindow : Window 17 { 18 List<task> taskList; 19 int taskPos; 20 DispatcherTimer timer = new DispatcherTimer(); 21 22 public MainWindow() 23 { 24 InitializeComponent(); 25 timer.Tick += exec; 26 } 27 28 private void button_Click(object sender, RoutedEventArgs e) 29 { 30 taskPos = 0; 31 taskList = new List<task>(); 32 taskList.Add(new task { Name = "Process1", Proc = Process1, Interval = 1 }); 33 taskList.Add(new task { Name = "Process2", Proc = Process2, Interval = 1 }); 34 taskList.Add(new task { Name = "Process3", Proc = Process3, Interval = 3 }); 35 taskList.Add(new task { Name = "Process1", Proc = Process1, Interval = 1 }); 36 taskList.Add(new task { Name = "Process2", Proc = Process2, Interval = 1 }); 37 taskList.Add(new task { Name = "Process3", Proc = Process3, Interval = 3 }); 38 Debug.WriteLine("タスクリスト開始"); 39 exec(this, EventArgs.Empty); 40 } 41 42 private void exec (object sender, EventArgs e) 43 { 44 timer.Stop(); 45 task task = taskList[taskPos]; 46 Debug.WriteLine(string.Format("{0} {1} 開始", DateTime.Now, task.Name)); 47 task.Proc.Invoke(task); 48 Debug.WriteLine(string.Format("{0} {1} 終了", DateTime.Now, task.Name)); 49 timer.Interval = TimeSpan.FromSeconds(task.Interval); 50 taskPos++; 51 if (taskPos < taskList.Count) { 52 timer.Start(); 53 } else { 54 Debug.WriteLine("タスクリスト完了"); 55 } 56 } 57 58 private void Process1(task task) 59 { 60 Debug.WriteLine(string.Format("{0} {1} 実行中", DateTime.Now, task.Name)); 61 } 62 63 private void Process2(task task) 64 { 65 Debug.WriteLine(string.Format("{0} {1} 実行中", DateTime.Now, task.Name)); 66 } 67 68 private void Process3(task task) 69 { 70 Debug.WriteLine(string.Format("{0} {1} 実行中", DateTime.Now, task.Name)); 71 } 72 } 73}

投稿2020/05/13 00:20

KOZ6.0

総合スコア2626

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

senkei_river

2020/05/13 10:20

ご回答ありがとうございます。大変わかりやすく、ソースコードも載せていただいたため、BAとさせていただきます。
guest

0

たんに処理3終了でタイマをリセット、スタートすればいいんでは

#提示のコードではどれが処理3かは不明ですが

投稿2020/05/12 23:37

y_waiwai

総合スコア87749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

senkei_river

2020/05/13 06:51

質問文でも補足させていただきましたが、処理の流れについて適切な説明になっていない点がありました。補足として記載させていただいてます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問