

初めまして、現在C#にて非同期処理を使ったプログラムを作成しています。

経緯として、ある外部機器のメモリ空間に、一定の値を連続して書き込むものを作りたいと考えました。  
その項目にチェックボックスを入れると、チェック中はasync/awaitを利用し、非同期処理で書き込む処理を続ける、というものを作りました。

ですが、同じ構造のものを複数作り、3つほどチェックを入れると、UIがフリーズしてしまいます。  
メモリへの書き込みは出来ているため、アプリケーションは落ちていないようです。

UIが固まるのはどういった原因が考えられるのでしょうか。

[code]

        #region Always UAV
    
        private async void kpUAV_CheckedChanged( object sender , EventArgs e )
        {
            if ( kpUAV.Checked )
            {
                while ( kpUAV.Checked )
                {
                    ulong targetClient = 0x21A8164 + (0x17010 * (ulong)kpSelectClient.Value ) ;
                    PS4.WriteMemory( this.processID , targetClient + 0x714      , new byte[]{ 0x01 } ) ; // UAV1
                    PS4.WriteMemory( this.processID , targetClient + 0xBC74     , new byte[]{ 0x01 } ) ; // UAV2
                    PS4.WriteMemory( this.processID , targetClient + 0x16F9C    , new byte[]{ 0x01 } ) ; // UAV3
                    await Task.Run( ( ) => { Thread.Sleep( 150 ) ; } ) ;
                }
            }
            else
            {
                ulong targetClient = 0x21A8164 + (0x17010 * (ulong)kpSelectClient.Value ) ;
                PS4.WriteMemory( this.processID , targetClient + 0x714      , new byte[]{ 0x00 } ) ; // UAV1
                PS4.WriteMemory( this.processID , targetClient + 0xBC74     , new byte[]{ 0x00 } ) ; // UAV2
                PS4.WriteMemory( this.processID , targetClient + 0x16F9C    , new byte[]{ 0x00 } ) ; // UAV3
            }
        }
    
        #endregion
    
        #region Always VSAT
    
        private async void kpVSAT_CheckedChanged( object sender , EventArgs e )
        {
            if ( kpVSAT.Checked )
            {
                while ( kpVSAT.Checked )
                {
                    ulong targetClient = 0x21A8164 + (0x17010 * (ulong)kpSelectClient.Value ) ;
                    PS4.WriteMemory( this.processID , targetClient + 0x718      , new byte[]{ 0x01 } ) ; // VSAT1
                    PS4.WriteMemory( this.processID , targetClient + 0xBC78     , new byte[]{ 0x01 } ) ; // VSAT2
                    PS4.WriteMemory( this.processID , targetClient + 0x16FA0    , new byte[]{ 0x01 } ) ; // VSAT3
                    await Task.Run( ( ) => { Thread.Sleep( 150 ) ; } ) ;
                }
            }
            else
            {
                ulong targetClient = 0x21A8164 + (0x17010 * (ulong)kpSelectClient.Value ) ;
                PS4.WriteMemory( this.processID , targetClient + 0x718      , new byte[]{ 0x00 } ) ; // VSAT1
                PS4.WriteMemory( this.processID , targetClient + 0xBC78     , new byte[]{ 0x00 } ) ; // VSAT2
                PS4.WriteMemory( this.processID , targetClient + 0x16FA0    , new byte[]{ 0x00 } ) ; // VSAT3
            }
        }
    
        #endregion
    
        #region Laser locator
    
        private async void kpLaserLocator_CheckedChanged( object sender , EventArgs e )
        {
            if (  kpLaserLocator.Checked )
            {
                while (  kpLaserLocator.Checked )
                {
                    ulong targetClient = 0x21A8164 + (0x17010 * (ulong)kpSelectClient.Value ) ;
                    PS4.WriteMemory( this.processID , targetClient + 0x782      , new byte[]{ 0x01 } ) ; // Point laser1
                    PS4.WriteMemory( this.processID , targetClient + 0xBCE2     , new byte[]{ 0x01 } ) ; // Point laser2
                    PS4.WriteMemory( this.processID , targetClient + 0x17740    , new byte[]{ 0x01 } ) ; // Point laser3
                    await Task.Run( ( ) => { Thread.Sleep( 150 ) ; } ) ;
                }
            }
            else
            {
                ulong targetClient = 0x21A8164 + (0x17010 * (ulong)kpSelectClient.Value ) ;
                PS4.WriteMemory( this.processID , targetClient + 0x782      , new byte[]{ 0x00 } ) ; // Point laser1
                PS4.WriteMemory( this.processID , targetClient + 0xBCE2     , new byte[]{ 0x00 } ) ; // Point laser2
                PS4.WriteMemory( this.processID , targetClient + 0x17740    , new byte[]{ 0x00 } ) ; // Point laser3
            }
        }
    
        #endregion
    
[/code]

[![左のチェックボックスを3つほどつけるとUIがフリーズします](https://i.stack.imgur.com/KgmSV.png)](https://i.stack.imgur.com/KgmSV.png)


CC BY-SA 4.0
2018-08-25T19:07:25.720
47812
2018-11-26T16:02:10.370
2018-08-25T22:56:35.007
19110
29866
question
c# マルチスレッド gui
Visual C# で非同期処理(async/await)を複数動かすとUIがフリーズする


原因では無くて調査方法ですが。これらを参考にデバッグしてみてください。

[マルチスレッド アプリケーションのデバッグ](https://docs.microsoft.com/ja-
jp/visualstudio/debugger/debug-multithreaded-applications-in-visual-studio)  
[同時実行ビジュアライザー](https://docs.microsoft.com/ja-
jp/visualstudio/profiling/concurrency-visualizer)

[Application Verifier](https://docs.microsoft.com/en-
us/windows/desktop/Win7AppQual/application-verifier)

タスクマネージャやプロセスエクスプローラでミニダンプを採取して、そのダンプを調査する。  
[How to Capture a Minidump: Let Me Count the
Ways](https://stackoverflow.com/questions/52022669/how-ios-detects-network-
printer-automatically)

これも色々なテクニックの解説。Part 1から5まであり。  
[Part 1: Windows Debugging Techniques - Debugging Application Crash
(Windbg)](https://www.codeproject.com/Articles/707488/Part-1-Windows-
Debugging-Techniques-Debugging-Appl)


CC BY-SA 4.0
2018-08-26T06:24:38.423
47815
2018-08-26T06:24:38.423
26370
47812
answer


解決していないようであればご参考までに。。。  
間違っていれば修正等お願いします。

`Thread.Sleep()`を使うとメインで動かしているUIを止めてしまうと私は記憶しています。  
これを解決するために`Thread.Sleep()`ではなく`Task.Delay()`というものが使用できると思います。  
コード内の`await Task.Run( ( ) => { Thread.Sleep( 150 ) ; } ) ;`を`await
Task.Delay(150);`に変更してご希望どおりの動作が確認できるようであれば幸いです。


CC BY-SA 4.0
2018-10-22T13:20:28.443
49538
2018-10-22T13:20:28.443
30634
47812
answer


Visual Studio 2017、.NET Framework 4.5のFormアプリケーションで検証してみました。

まず`PS4.WriteMemory`抜きで同様のコードを動かしてみた感じでは、チェックボックスを3つ入れても動作が重くなる現象は再現しませんでした。  
`async`、`await`、`Task`の使い方は問題ないようです。  
念の為`PS4.WriteMemory`が呼ばれている箇所で`Thread.CurrentThread.ManagedThreadId`を呼び出してスレッドIDも確認しましたが、すべて"1"だったのでメインスレッドでした。  
同一スレッド上の実行であれば、`PS4.WriteMemory`がスレッドセーフで無かったとしても問題ないでしょう。

考えられる可能性は、単純に`PS4.WriteMemory`の処理に時間がかかっていることが考えられます。  
コードではスリープしている時間は150msなので、`PS4.WriteMemory`×n個の処理が150msを超えるようであれば、処理時間が待機時間を上回るのでUIが応答しなくなると思われます。  
試しに`PS4.WriteMemory`×3個分を`Thread.Sleep(70)`として配置すると、チェックボックスを3つ入れた段階でほぼ操作不能に陥りました。

手っ取り早い解決策は、`Task`内のスリープ時間を伸ばすことです。  
待機時間が処理時間よりもずっと大きければ、重いでしょうが操作は可能です。  
抜本的な解決策としては、`PS4.WriteMemory`の処理を`System.Threading.Timer`内で行うことが考えれます。  
チェックボックスごとに`Timer`を作り、`Timer`の開始と停止を制御するような形にします。  
別スレッドの処理となるため、排他制御が必要となります。  
またアプリケーションの終了時には、`Timer.Dispose()`を呼び出して解放してください。


CC BY-SA 4.0
2018-10-25T15:16:16.443
49663
2018-10-25T15:16:16.443
70
47812
answer