C#における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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
using System;
using System.Threading.Task;
namespace testApp001 {
class Test001 {
async Task 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
2
3
4
|
Main Method
StartasyncProc Start(call sleepAndAsync)
sleepAndAsync Start(sleep)
Main Method End
|
となり、「Task.Deley」メソッドが非同期で実行されるので、”sleepAndAsync Start(sleep)”以降のコンソール出力が”Main Methood End”まで出力されないようになります。
厳密な時間で待機処理をする場合
冒頭で説明の通りC#で厳密な時間で待機処理をする場合、「Thread.Sleep」メソッドでは精度に限界があります。
このような場合は以下のような実装で回避する事が可能です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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」メソッドは簡単に実装できます。
しかし少しの注意を払う事で、更にC#プログラム実装の幅が広がります。
マイクロソフトには『C#関連のドキュメント』というサイトがあり、色々なサンプルやリファレンスが充実しています。
また更に高みを目指す方は、C#において「マルチスレッド」の説明を重点的に行っている文献も多数ありますので、色々と活用してみてください。
ネプラス株式会社はサービス開始から10年以上
『エンジニアの生涯価値の向上』をミッションに掲げ、
多くのインフラエンジニア・ネットワークエンジニアの就業を支援してきました。
ネプラス株式会社はこんな会社です
秋葉原オフィスにはネプラス株式会社をはじめグループのIT企業が集結!
数多くのエンジニアが集まります。

-
インフラ業界に特化
ネットワーク・サーバー・データベース等、ITインフラ業界に特化。Cisco Systemsプレミアパートナーをはじめ各種ベンダーのパートナー企業です。
業界を知り尽くしているからこそ大手の取引先企業、経験豊富なエンジニアに選ばれています。
-
正社員なのにフリーランスのような働き方
正社員の方でも希望を聞いたうえでプロジェクトをアサインさせていただいており、フリーランスのような働き方が可能。帰社日もありません。
プロジェクト終了後もすぐに次の案件をご紹介させていただきますのでご安心ください。
-
大手直取引の高額案件
案件のほとんどが大手SIerやエンドユーザーからの直取引のためエンジニアの皆様へに高く還元できています。
Ciscoをはじめ、Juniper、Azure、Linux、AWS等インフラに特化した常時300件以上の案件があります。
-
スキルアップ支援
不要なコストを削減し、その分エンジニアの方へのスキルアップ支援(ネットワーク機器貸出、合格時の受験費用支給など)や給与で還元しています。
受験費用例)CCNP,CCIE:6-20万円、JNCIS:3-4万円、AWS:1-3万円など
※業務に関連する一定の資格のみ。各種条件がありますので詳しくは担当者へにお尋ねください。
-
現給与を保証します!※
前職の給与保証しており、昨年度は100%の方が給与アップを実現。収入面の不安がある方でも安心して入社していただけます。
※適用にはインフラエンジニアの業務経験1年以上、等一定の条件がございます。
-
インセンティブ制度
ネットワーク機器の販売・レンタル事業等、売上に貢献いただいた方にはインセンティブをお支払いしています。
取引先企業とエンジニア側、双方にメリットがあり大変好評をいただいています。
-
社会保険・福利厚生
社員の方は、社会保険を完備。健康保険は業界内で最も評価の高い「関東ITソフトウェア健康保険組合」です。
さらに様々なサービスをお得に利用できるベネフィットステーションにも加入いただきます。
-
東証プライム上場企業グループ
ネプラスは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。
安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。
ネプラス株式会社に興味を持った方へ
ネプラス株式会社では、インフラエンジニアを募集しています。
年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
オンライン面接も随時受付中。ぜひお気軽にご応募ください。

