C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: システムが処理を握ってしまう場合のProgressBar更新


(過去ログ 137 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■80681 / inTopicNo.1)  システムが処理を握ってしまう場合のProgressBar更新
  
□投稿者/ 政吉 (1回)-(2016/08/02(Tue) 19:51:38)

分類:[C#] 

2016/08/02(Tue) 19:55:02 編集(投稿者)
2016/08/02(Tue) 19:52:39 編集(投稿者)
2016/08/02(Tue) 19:52:19 編集(投稿者)

政吉と申します。

SDKはVisual Studio Comunity 2015を使用しています。 
現在マイコンを搭載した基板とPCをUSB通信ケーブルで接続し、マイコンとシリアル通信を行うPC側のアプリを
作成しています。
USBを使用していますが、マイコンメーカが提供しているUSBを仮想COMポートとして認識するドライバにより、
PC側アプリはCOM Portに対してシリアル通信を行う形式です。

別途、PC側のアプリ内で、グラフ表示してグラフ上の線をマウスやタッチパネルで掴んで操作みたいなことを
やりたいので、基本的にはWPFでプログラミングしています。

ここで、マイコン側の問題か、仮想COMポートドライバの問題か、COMポートのオープン処理に1分程度の時間が
かかります。
具体的には、
    serialPort.Open();
の処理を実行すると、この処理が1分程度、返ってきません。


この為、この間に別WindowでProgressBarを表示したいと思い、下記のようなコードを作成してみました。
↓COMポートオープン処理時

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        string ComPort = "COM3";

        frmProgressBar f = new ParamSettingWPF.frmProgressBar();
        f.Show();    // ProgressBarのFormを開く
    
        serialPort = new SerialPort(ComPort, 115200, Parity.None, 8, StopBits.One);
        serialPort.Open();  // シリアルポートオープン

//        f.Dispose();    // ProgressBarのForm閉じる
〜以下省略


↓ProgressBarが貼り付けてあるForm 
 timer1のインターバルは1秒設定で、60秒ProgressBarで進捗表示させると共に
 label1に60秒のカウントダウン数字を表示させようとしています。


    public partial class frmProgressBar : Form
    {
        public frmProgressBar()
        {
            InitializeComponent();
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            int cnt;
            if (progressBar1.Maximum < progressBar1.Value)
            {
                progressBar1.Value++;
            }
            cnt = int.Parse(label1.Text);
            cnt--;
            label1.Text = cnt.ToString();
        }
    }


ですが、実際に実行させてみると、ProgressBarのFormは表示されるのですが、serialPort.Open();の処理に
入った後、timer1_Tickにブレークを張っても引っかからず、ProgressBarやLabelの値が進捗しません。
serialPort.Open();の処理を抜けた後から、timer1_Tickに張ったブレークに引っかかるようになり、
ProgressBarやLabelの値が進捗するようになります。

serialPort.Open()がアプリの処理を握ってしまっている為、ProgressBar等の表示更新はできないのでしょか?
ちなみに、serialPort.Open()の処理が1分かかっている状態でもタスクマネージャを開いて確認したところ、
CPU使用率は6%〜8%程度なのでCPU的に空きがない状態ではなさそうです。

何か良い方法はありませんでしょうか?

引用返信 編集キー/
■80682 / inTopicNo.2)  Re[1]: システムが処理を握ってしまう場合のProgressBar更新
□投稿者/ かたぎり (2回)-(2016/08/02(Tue) 21:41:41)
ヒントになると思うURLをはっときますね。

https://msdn.microsoft.com/ja-jp/library/cc221403%28v=vs.95%29.aspx?f=255&MSPPError=-2147217396

こちらが参考になるかと。

No80681 (政吉 さん) に返信
> 2016/08/02(Tue) 19:55:02 編集(投稿者)
> 2016/08/02(Tue) 19:52:39 編集(投稿者)
> 2016/08/02(Tue) 19:52:19 編集(投稿者)
>
> 政吉と申します。
>
> SDKはVisual Studio Comunity 2015を使用しています。
> 現在マイコンを搭載した基板とPCをUSB通信ケーブルで接続し、マイコンとシリアル通信を行うPC側のアプリを
> 作成しています。
> USBを使用していますが、マイコンメーカが提供しているUSBを仮想COMポートとして認識するドライバにより、
> PC側アプリはCOM Portに対してシリアル通信を行う形式です。
>
> 別途、PC側のアプリ内で、グラフ表示してグラフ上の線をマウスやタッチパネルで掴んで操作みたいなことを
> やりたいので、基本的にはWPFでプログラミングしています。
>
> ここで、マイコン側の問題か、仮想COMポートドライバの問題か、COMポートのオープン処理に1分程度の時間が
> かかります。
> 具体的には、
> serialPort.Open();
> の処理を実行すると、この処理が1分程度、返ってきません。
>
>
> この為、この間に別WindowでProgressBarを表示したいと思い、下記のようなコードを作成してみました。
> ↓COMポートオープン処理時
>
> private void Window_Loaded(object sender, RoutedEventArgs e)
> {
> string ComPort = "COM3";
>
> frmProgressBar f = new ParamSettingWPF.frmProgressBar();
> f.Show(); // ProgressBarのFormを開く
>
> serialPort = new SerialPort(ComPort, 115200, Parity.None, 8, StopBits.One);
> serialPort.Open(); // シリアルポートオープン
>
> // f.Dispose(); // ProgressBarのForm閉じる
> 〜以下省略
>
>
> ↓ProgressBarが貼り付けてあるForm 
>  timer1のインターバルは1秒設定で、60秒ProgressBarで進捗表示させると共に
>  label1に60秒のカウントダウン数字を表示させようとしています。
>
>
> public partial class frmProgressBar : Form
> {
> public frmProgressBar()
> {
> InitializeComponent();
> timer1.Start();
> }
>
> private void timer1_Tick(object sender, EventArgs e)
> {
> int cnt;
> if (progressBar1.Maximum < progressBar1.Value)
> {
> progressBar1.Value++;
> }
> cnt = int.Parse(label1.Text);
> cnt--;
> label1.Text = cnt.ToString();
> }
> }
>
>
> ですが、実際に実行させてみると、ProgressBarのFormは表示されるのですが、serialPort.Open();の処理に
> 入った後、timer1_Tickにブレークを張っても引っかからず、ProgressBarやLabelの値が進捗しません。
> serialPort.Open();の処理を抜けた後から、timer1_Tickに張ったブレークに引っかかるようになり、
> ProgressBarやLabelの値が進捗するようになります。
>
> serialPort.Open()がアプリの処理を握ってしまっている為、ProgressBar等の表示更新はできないのでしょか?
> ちなみに、serialPort.Open()の処理が1分かかっている状態でもタスクマネージャを開いて確認したところ、
> CPU使用率は6%〜8%程度なのでCPU的に空きがない状態ではなさそうです。
>
> 何か良い方法はありませんでしょうか?
引用返信 編集キー/
■80683 / inTopicNo.3)  Re[1]: システムが処理を握ってしまう場合のProgressBar更新
□投稿者/ 774RR (443回)-(2016/08/02(Tue) 21:45:39)
Window_Loaded() に直接 SerialPort.Open() を記述しているということは
SerialPort.Open() が完了するまで UI スレッドをブロックしているということで

> serialPort.Open()がアプリの処理を握ってしまっている為、ProgressBar等の表示更新はできないのでしょか?
そのとおり
そのためのマルチスレッド (UI とバックグラウンド作業の分離) なので、マルチスレッド化を考えよう。
シリアル入出力は専用のスレッドで行って UI と分離するとよいだろう。

古い .NET Framework で動く必要があるなら昔ながらの Thread を使ってもいいし、
.NET 4.5 (だっけ?) 以後対象なら、より簡単な async / await 機構を使ってもい。
どう使えばよいかは、ここの過去ログでもいいし普通に google 様にでも尋ねてみるといい。
# オイラが解説してもいいんだけど週末までちと忙しいのでほかの方にお任せで。

Open() に1分は尋常ではないので「開くのが遅い」理由を追求してみるのも悪くないけど。
COM ハードウエアの不具合とか COM ドライバのバグとかありそうな気もするし。

引用返信 編集キー/
■80684 / inTopicNo.4)  Re[1]: システムが処理を握ってしまう場合のProgressBar更新
□投稿者/ 魔界の仮面弁士 (794回)-(2016/08/02(Tue) 21:46:35)
No80681 (政吉 さん) に返信
> ↓ProgressBarが貼り付けてあるForm 

System.Windows.Controls.ProgressBar ではなく、
System.Windows.Forms.ProgressBar を使うのですね?


> label1に60秒のカウントダウン数字を表示させようとしています。

Value を更新させているということは、ProgressBar はマーキースタイルでは無いのですね。
オープン処理に要する時間は、常にピッタリ 60 秒間なのでしょうか。


> timer1_Tickにブレークを張っても引っかからず

イベント処理の多くは、何も実行していない「アイドル時」に呼び出されます。

ですから、UI スレッドが時間のかかる処理を行っている場合、
画面の更新や Timer_Tick の受信などは行われないというわけです。


今回の件に限らず、時間のかかる処理がある場合は、UI スレッドに
担当させるのではなく、他のスレッドで非同期処理させてみてください。
引用返信 編集キー/
■80688 / inTopicNo.5)  Re[2]: システムが処理を握ってしまう場合のProgressBar更新
□投稿者/ 政吉 (2回)-(2016/08/03(Wed) 11:29:16)
かたぎり様、774RR様、魔界の仮面弁士様
早急にレスいただき、ありがとうございます。

とりあえず、シリアル通信関連処理をasync/awaitを使って別タスクにする
方法で修正してみようと思います。
async/awaitは使ったことが無いのですが、とりあえずネット等で情報収集
して作成してみます。
本当に助かりました。

また何か壁にぶち当たりましたら質問させていただきます。
ありがとうございました。

引用返信 編集キー/
■80705 / inTopicNo.6)  Re[3]: システムが処理を握ってしまう場合のProgressBar更新
□投稿者/ 政吉 (3回)-(2016/08/04(Thu) 11:24:39)
No80688 (政吉 さん) に返信
> かたぎり様、774RR様、魔界の仮面弁士様
> 早急にレスいただき、ありがとうございます。
>
> とりあえず、シリアル通信関連処理をasync/awaitを使って別タスクにする
> 方法で修正してみようと思います。
> async/awaitは使ったことが無いのですが、とりあえずネット等で情報収集
> して作成してみます。
> 本当に助かりました。
>
> また何か壁にぶち当たりましたら質問させていただきます。
> ありがとうございました。
>
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -