C#におけるSleep処理とは?

- システム
エンジニア - C#におけるSleep処理とは、どのようなことができるのでしょうか?
- プロジェクト
マネージャー - まずはThread.Sleepメソッドから解説します。順序を追って理解していきましょう。
C#におけるSleep処理とは?
Thread.Sleepメソッド
C#の「Thread.Sleep」メソッド(「System.Threading」に存在)は、指定した時間の長さ、現在のスレッドを中断する処理です。このため、一般的に時間待機をするプログラムであれば良く用いられるメソッドです。またC#含め、「.NET Framework」の「Sleep」メソッドは「CPUの割り込み処理」で処理されます。このため、厳密な意味では引数で指定した時間待機処理をする訳ではない点には注意が必要です。単純な待機処理でかつ、厳密な時間計測が必要でない場合に利用します。なお「CPUの割り込み処理」が他のプログラムからも頻発する場合、CPUが別プロセスに利用されてしまいますので、「Thread.Sleep」メソッドを呼び出した際に設定した時間以上かかる場合があります。
Thread(スレッド)とは?
「Thread.Sleep」にある「Thread(スレッド)」という言葉を聞いて、ピンと来ない人も多いと思います。正直なところ、初心者の方はここで躓く事が多いのも事実です。C#以外のプログラムも含め、アプリケーションは2つに大別され、「マルチスレッド」「シングルスレッド」処理と呼ばれます。
「マルチスレッド」とは、ふんわり説明すると『聖徳太子』のように色々な話を同時にしても、ちゃんと聞き分けてそれぞれの担当者に適切に並列で指示をするような処理です。対義語として「シングルスレッド」というものがありますが、簡単に説明すると『1つの事しか片づけられない』人を思い浮かべてみてください。これをプログラムに当てはめて考えたのが「シングルスレッド」のプログラムになります。
正しく説明すると、例えばスマホアプリは基本的には「シングルスレッド」(同期処理)なので、アプリを切り替えないと裏に回ったアプリ処理は中断しています。※スマホの中でも、実際には電話やメール、その他通知機能を利用したバックグラウンドサービスはマルチスレッドで動いています。スマホと比較して、WindowsやMac、その他OSのプログラムは、同時に並列でプログラム処理を実行(非同期処理)しています。(Aプログラムを実行中に、待ち時間にブラウザで調べものをするような感じです。)
昔はタイムシェアリングという、1つのCPUで複数処理を同時にするために、CPU時間を等分配して細かな時間単位でCPU専用率を分割して、少ないリソース(資源)を共有利用していました。今やCPUにはコアと呼ばれる「脳」に相当するものが複数存在しますので、それぞれプログラム(スレッド)毎に自動的にCPUコアを割り当てて実行しているという形になります。(実際には、コアが複数あったとしても、それぞれの負荷に応じて処理が適切に分配されています。)「マルチスレッド」も「シングルスレッド」も、一長一短ですので、求められる処理によって使い分けが必要です。
Sleepメソッドの記述方法
C#では、2つの「Sleep」メソッドが準備されています。①引数にint型のミリ秒を利用した場合
1
|
public static void Sleep (int millisecondsTimeout);
|
引数「millisecondsTimeout」には、待機するミリ秒を記載します(1秒なら”1000″を記載)
②引数にTimeSpanクラスを利用した場合
1
|
public static void Sleep (TimeSpan timeout);
|
引数の「timeout」には、TimeSpan クラス変数で定義した引数を指定します。(詳細な説明は後述します。)いずれも引数が負の数であったり、「Int32.MaxValue」である”2147483647″を超える場合は「ArgumentOutOfRangeException」例外が発生します。
スレッド内の非同期処理について
ここからはC#において、スレッド処理を非同期にする際に「Thread.Sleep」を利用する場合の注意事項について触れたいと思います。C#において「マルチスレッド」の【非同期処理】を定義する場合、同一クラス内に「async」シグネチャを付けたメソッドが必要になり、これらメソッドが『非同期メソッド』になります。C#の『非同期メソッド』では、「await」キーワードが利用できるようになり、メソッドを呼び出す際に「await」キーワードを付ける事で、該当処理のタスク完了を待ち、その戻り値を取り出す事が可能になります。
この際に「Thread.Sleep」メソッドに「await」キーワードを付けると、『voidを待機することができません』というエラーになります。これはC#において、「void」メソッドに「await」キーワードを付けて呼び出す事が不可能であるために発生し、今回の「Thread.Sleep」メソッドが戻り値の無い「void」メソッド(関数)であることが原因です。このような場合、「void」型の「Thread.Sleep」メソッドではなく、「System.Threading.Tasks」に存在する、遅延を表す「Task」クラスを返却する「Task.Delay」メソッドを利用します。
1
|
using System;using System.Threading.Tasks;namespace testApp001 { class Test001 { async Task<String> sleepAndAsync (String str) { Console.WriteLine ("sleepAndAsync Start(sleep)"); // await Thread.Sleep (2000); この呼び方がエラーになる await Task.Delay (2000); Console.WriteLine ("sleepAndAsync End"); return "Argument:" + str; } async void asyncProc () { Console.WriteLine ("asyncProc Start(call sleepAndAsync)"); var res = await sleepAndAsync ("call from asyncProc"); Console.WriteLine (res); Console.WriteLine ("asyncProc End"); } static void Main (string[] args) { Console.WriteLine ("Main Method Start"); var app = new Test001 (); app.asyncProc (); Console.WriteLine ("Main Method End"); } }}
|
といった記述が必要になります。C#開発において【非同期処理】内で「Thread.Sleep」メソッドの利用は出来ません。「Task.Delay」メソッドを「await」シグネチャを付けて呼び出す事で非同期実行になります。処理結果は
1
|
Main Method StartasyncProc Start(call sleepAndAsync)sleepAndAsync Start(sleep)Main Method End
|
となり、「Task.Deley」メソッドが非同期で実行されるので、”sleepAndAsync Start(sleep)”以降のコンソール出力が”Main Methood End”まで出力されないようになります。
厳密な時間で待機処理をする場合
冒頭で説明の通りC#で厳密な時間で待機処理をする場合、「Thread.Sleep」メソッドでは精度に限界があります。このような場合は以下のような実装で回避する事が可能です。
1
|
using System;using System.Diagnostics;using System.Threading;namespace TestApp002 { class Test002 { static void Main (string[] args) { Stopwatch sw = new Stopwatch (); sw.Start (); while (true) { Thread.Sleep (1); if (sw.ElapsedMilliseconds > 1000) break; } Console.WriteLine (sw.ElapsedMilliseconds); sw.Stop (); } }}
|
実際に「Thread.Sleep(1000);」と記載するより、処理の中断時間が厳密に計測できます。なお処理結果には
1
|
1001
|
1
|
1002
|
と表示され、「Thread.Sleep」メソッドが他の処理割り込みで時間がずれるのを防ぐ効果があります。
- システム
エンジニア - Thread.Sleepメソッドを理解すれば、簡単に実装できるのですね。
- プロジェクト
マネージャー - そうですね。さらに高いレベルを目指すのであれば、マルチスレッドも習得してみましょう!
最後に
「Thread.Sleep」メソッドは簡単に実装できます。しかし少しの注意を払う事で、更にC#プログラム実装の幅が広がります。マイクロソフトには『C#関連のドキュメント』というサイトがあり、色々なサンプルやリファレンスが充実しています。また更に高みを目指す方は、C#において「マルチスレッド」の説明を重点的に行っている文献も多数ありますので、色々と活用してみてください。
FEnet.NETナビ・.NETコラムは株式会社オープンアップシステムが運営しています。
株式会社オープンアップシステムはこんな会社です
秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
数多くのエンジニアが集まります。

-
スマホアプリから業務系システムまで
スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。
-
充実した研修制度
毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。
-
資格取得を応援
スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。
-
東証プライム上場企業グループ
オープンアップシステムは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。
安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。
株式会社オープンアップシステムに興味を持った方へ
株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。
年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。


C#新着案件New Job
-
システム開発/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(新宿駅) -
システム開発/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(新宿駅) -
デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円神奈川県横浜市(桜木町駅) -
デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円神奈川県横浜市(桜木町駅) -
基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(西新宿駅) -
基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(西新宿駅)