MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C Sharpの基礎 - 排他制御のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C Sharpの基礎 - 排他制御
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 排他制御は、複数のスレッドやプロセスが共有リソースに同時にアクセスすることによって発生する競合状態を防ぐことが主な目的である。<br> <br> C#では、以下に示すような排他制御メカニズムが提供されている。<br> * lockステートメント *: 最も簡単な同期プリミティブであり、モニタロックを取得するためのシンタックスを提供する。 *: 内部的には、Monitorクラスを使用している。 *: <syntaxhighlight lang="c#"> private static readonly object _lock = new object(); public void SafeMethod() { lock (_lock) { // 排他的にアクセスする処理 // ...略 } } </syntaxhighlight> *: <br> * Monitorクラスの直接的な使用 *: 高度な制御が必要な場合、Monitorクラスを直接的に使用することにより、タイムアウトの設定やロックの状態確認等が可能になる。 *: <br> * SemaphoreSlim *: 非同期処理における排他制御として、同一のプロセスの場合はSemaphoreSlimを使用することが推奨される。 *: 軽量で高性能な同期プリミティブであり、async / awaitパターンとの相性が良い。 *: MutexおよびSemaphore *: プロセス間同期が必要な場合は、MutexやSemaphoreを使用する。 *: これは、OSレベルの同期機構を提供しており、異なるプロセス間での調整が可能である。 *: ただし、システムリソースを消費するため、同一プロセス内での使用はlockステートメントやSemaphoreSlimが推奨される。 *: <br> * ReaderWriterLockSlim *: 読み書き問題に対応するためのReaderWriterLockSlimも提供されている。 *: これは読み取り操作が多く、書き込み操作が少ない状況で特に有効となる。 *: 複数の読み取りスレッドを同時に許可しながら、書き込み時の排他制御を実現することができる。 <br> さらに重要な概念として、インターロック操作がある。<br> Interlockedクラスは、アトミックな操作を提供しており、カウンタのインクリメントやデクリメント等の単純な操作を安全に行うことができる。<br> <br> 排他制御を実装するにあたり、デッドロックの防止が挙げられる。<br> 複数のロックを取得する必要がある場合は、常に同じ順序でロックを取得する等、一貫性のあるアプローチが必要である。<br> <br> また、パフォーマンスにおいては、ロックの範囲は必要最小限に抑えることが重要である。<br> 長時間のロック保持は、並行処理の利点を失わせ、アプリケーション全体のスケーラビリティを低下させる可能性がある。<br> <br> 細かい粒度での制御が必要な場合、volatileキーワードやメモリバリアを使用することにより、低レベルでの同期制御も可能であるが、使用には深い知識が必要となる。<br> <br><br> == SemaphoreSlim == 最も軽量で、軽量で、非同期操作に最適化されたセマフォを使用する。<br> メモリ使用量が少なく、パフォーマンスが高い。<br> <br> <u>ただし、同一プロセス内での排他制御では推奨されるが、異なるプロセス間での排他制御には適していない。</u><br> <br> <syntaxhighlight lang="c#"> // 軽量で、非同期操作に最適化されたセマフォを使用 private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); public static async Task AccessFileAsync() { // セマフォの取得を待機 try { await semaphore.WaitAsync(); try { // ファイルの読み書き await File.WriteAllTextAsync("sample.txt", "データ" + DateTime.Now); string content = await File.ReadAllTextAsync("sample.txt"); Console.WriteLine($"読み取り結果 : {content}"); } catch (IOException ex) { Console.WriteLine($"ファイルアクセスエラー : {ex.Message}"); throw; // 上位層で処理するように再スロー } catch (UnauthorizedAccessException ex) { // アクセス権限に関する例外処理 Console.WriteLine($"アクセス権限エラー : {ex.Message}"); throw; } finally { semaphore.Release(); } } catch (OperationCanceledException) { // WaitAsyncメソッドがキャンセルされた場合の処理 Console.WriteLine("セマフォの取得がキャンセルされました"); throw; } } // 使用例 try { var tasks = new List<Task>(); for (int i = 0; i < 5; i++) { tasks.Add(AccessFileAsync()); } await Task.WhenAll(tasks); tasks.Clear(); } catch (Exception ex) { Console.WriteLine($"実行中にエラーが発生 : {ex.Message}"); } </syntaxhighlight> <br><br> == Mutex == 異なるプロセス間での排他制御が可能である。<br> システム全体でのグローバルな名前を持つことができる。<br> <br> タイムアウト機能を実装しやすい。<br> <br> ただし、SemaphoreSlimと比較してオーバーヘッドが大きいことに注意する。<br> <br> <u>※注意</u><br> <u>重層的な例外処理が必要となる。</u><br> * <u>Mutexの作成時の例外</u> * <u>WaitOneメソッドでのAbandonedMutexException例外</u> * <u>ReleaseMutexでの例外</u> * <u>ファイルアクセスの例外</u> <br> <syntaxhighlight lang="c#"> // プロセス間での排他制御が必要な場合に使用 private const string MutexName = "GlobalFileMutex"; public static async Task AccessFileAsync() { Mutex mutex = null; try { mutex = new Mutex(false, MutexName); // Mutexの取得を待機 (タイムアウトを30秒とする) bool hasMutex = false; try { hasMutex = mutex.WaitOne(TimeSpan.FromSeconds(30)); if (!hasMutex) { throw new TimeoutException("Mutexの取得がタイムアウトしました"); } try { // ファイルの読み書き await File.WriteAllTextAsync("sample.txt", "データ" + DateTime.Now); string content = await File.ReadAllTextAsync("sample.txt"); Console.WriteLine($"読み取り結果 : {content}"); } catch (IOException ex) { Console.WriteLine($"ファイルアクセスエラー : {ex.Message}"); throw; } catch (UnauthorizedAccessException ex) { Console.WriteLine($"アクセス権限エラー : {ex.Message}"); throw; } } catch (AbandonedMutexException) { // 別プロセスが終了してMutexが放棄された場合の処理 Console.WriteLine("Mutexが放棄されました"); throw; } finally { if (hasMutex) { try { mutex.ReleaseMutex(); } catch (ApplicationException ex) { // ReleaseMutexに失敗した場合の処理 Console.WriteLine($"Mutexの解放に失敗 : {ex.Message}"); } } } } catch (UnauthorizedAccessException ex) { // Mutex作成時のアクセス権限エラー Console.WriteLine($"Mutexの作成に失敗 : {ex.Message}"); throw; } finally { mutex?.Dispose(); } } // 使用例 try { var tasks = new List<Task>(); for (int i = 0; i < 5; i++) { tasks.Add(AccessFileAsync()); } await Task.WhenAll(tasks); tasks.Clear(); } catch (Exception ex) { Console.WriteLine($"実行中にエラーが発生 : {ex.Message}"); } </syntaxhighlight> <br><br> == FileStreamクラスのFile Shareモード == FileShareモードを細かく制御可能である。<br> <br> ファイルシステムレベルでの排他制御が可能なため、ファイルシステムレベルでの厳密な制御が必要な場合にする。<br> <br> <u>※注意</u><br> <u>ただし、長時間ファイルをロックする可能性があるため注意が必要である。</u><br> <br> <syntaxhighlight lang="c#"> // ファイルシステムレベルでの排他制御を行う public static async Task AccessFileAsync() { try { // FileShareNoneで他のプロセスからのアクセスを完全にブロック using (FileStream fs = new FileStream("sample.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { using (StreamWriter writer = new StreamWriter(fs)) using (StreamReader reader = new StreamReader(fs)) { try { // ファイルの書き込み await writer.WriteLineAsync("データ" + DateTime.Now); await writer.FlushAsync(); // ストリームの位置を先頭に戻す fs.Position = 0; // ファイルの読み取り string content = await reader.ReadToEndAsync(); Console.WriteLine($"読み取り結果 : {content}"); } catch (IOException ex) { Console.WriteLine($"ストリーム操作エラー : {ex.Message}"); throw; } } } } catch (IOException ex) { // ファイルが他のプロセスによってロックされている場合 Console.WriteLine($"ファイルアクセスエラー : {ex.Message}"); throw; } catch (UnauthorizedAccessException ex) { Console.WriteLine($"アクセス権限エラー : {ex.Message}"); throw; } } // 使用例 try { var tasks = new List<Task>(); for (int i = 0; i < 5; i++) { tasks.Add(AccessFileAsync()); } await Task.WhenAll(tasks); tasks.Clear(); } catch (Exception ex) { Console.WriteLine($"実行中にエラーが発生 : {ex.Message}"); } </syntaxhighlight> <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:C_Sharp]]
C Sharpの基礎 - 排他制御
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse