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

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

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

Re[8]: bgWorkerにおけるusingのbreak


(過去ログ 82 を表示中)

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

■48824 / inTopicNo.1)  bgWorkerにおけるusingのbreak
  
□投稿者/ Jem (3回)-(2010/04/15(Thu) 01:27:47)

分類:[C#] 

2010/04/15(Thu) 01:29:58 編集(投稿者)
2010/04/15(Thu) 01:29:38 編集(投稿者)
2010/04/15(Thu) 01:29:34 編集(投稿者)

<pre><pre>こんばんは。Jemです。

BackgroundWorkerを実行している途中、キャンセルアクションを入れbreakさせました。
breakはするのですが、スレッドの終了処理(RunWorkerCompleted)に到達せず、スレッドがスリープ状態になってしまいます。
ステップインでおってみると、returnのところで処理が終了します。

どこか間違っているのでしょうか?
同じソースをもとに、usingの部分をコメントアウトしたところ、正常にスレッド終了処理に到達しました。
#RunWorkerCompletedは正しく設定されている。


        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {

            using (StreamReader reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    if (worker.CancellationPending)
                    {
                        Console.WriteLine("###worker.CancellationPending");
                        break;
                    }

                }
                e.Cancel = true;
                return;
            }
            //下記が実行されない
            Console.WriteLine("the end of DoWork");
        
        }</pre></pre>

引用返信 編集キー/
■48825 / inTopicNo.2)  Re[1]: bgWorkerにおけるusingのbreak
□投稿者/ Hongliang (603回)-(2010/04/15(Thu) 02:21:13)
いやそりゃ return したらメソッド抜けますよ。BackgroundWorker 以前の、当然の話。
// そもそもコンパイル時に「到達できないコードが検出されました」って警告が出てるはず。
using してるから StreamReader は途中で return しててもちゃんと Close されますけど。

> while (!reader.EndOfStream)
> {
> if (worker.CancellationPending)
> {
> Console.WriteLine("###worker.CancellationPending");
> break;
> }
> }
> e.Cancel = true;
これおかしいですよね? CancellationPending に関わらず、最終的に常に Cancel が true になってしまってる。
引用返信 編集キー/
■48826 / inTopicNo.3)  Re[2]: bgWorkerにおけるusingのbreak
□投稿者/ Jem (4回)-(2010/04/15(Thu) 02:33:30)
No48825 (Hongliang さん) に返信
仰る通りです…。return後のConsole.WriteLineは実行される訳がありませんね。

ただ気になるのはreturn後にRunWorkerCompletedで終了処理がされないのはなぜなんでしょうか。

> いやそりゃ return したらメソッド抜けますよ。BackgroundWorker 以前の、当然の話。
> // そもそもコンパイル時に「到達できないコードが検出されました」って警告が出てるはず。
> using してるから StreamReader は途中で return しててもちゃんと Close されますけど。
>
>>while (!reader.EndOfStream)
>>{
>> if (worker.CancellationPending)
>> {
>> Console.WriteLine("###worker.CancellationPending");
>> break;
>> }
>>}
>>e.Cancel = true;
> これおかしいですよね? CancellationPending に関わらず、最終的に常に Cancel が true になってしまってる。
引用返信 編集キー/
■48832 / inTopicNo.4)  Re[3]: bgWorkerにおけるusingのbreak
□投稿者/ よねKEN (468回)-(2010/04/15(Thu) 09:41:21)
No48826 (Jem さん) に返信
> ただ気になるのはreturn後にRunWorkerCompletedで終了処理がされないのはなぜなんでしょうか。

その判断は正しいのでしょうか?
RunWorkerCompletedが実行されていないというのはどのように判断しましたか?

> #RunWorkerCompletedは正しく設定されている。

本当に正しく設定されているのですか?
どのように設定したのですか?正しく設定できているというのはどのように判断したのですか?

上記の2点について、そう考えた根拠が示されていませんので読者が判断できる状態にありません。
読者が実際に動かして検証できるコードがあるわけでもないので、
正しく設定されている、RunWorkerCompletedが処理されていない、と言われても、
「何ででしょうね、何か勘違いかミスをしているのでしょうね」としか言いようがありません。

その辺を明確にしてはいかがでしょうか。
引用返信 編集キー/
■48833 / inTopicNo.5)  Re[4]: bgWorkerにおけるusingのbreak
□投稿者/ なちゃ (423回)-(2010/04/15(Thu) 10:03:52)
実はキャンセル時はキャンセルしたあと即座にフォームを閉じてるとか、そんなことあったりします?

引用返信 編集キー/
■48844 / inTopicNo.6)  Re[5]: bgWorkerにおけるusingのbreak
□投稿者/ おのでら (7回)-(2010/04/15(Thu) 12:14:47)
おのでら さんの Web サイト
StreamReader.EndOfStream で末端チェックしているのはいいですが肝心の読み込み処理がないですね・・・
引用返信 編集キー/
■48850 / inTopicNo.7)  Re[6]: bgWorkerにおけるusingのbreak
□投稿者/ Jem (5回)-(2010/04/15(Thu) 13:36:09)
2010/04/15(Thu) 13:40:00 編集(投稿者)
みなさま

Jemです。質問内容に不備があり大変申し訳ありません。
インラインで回答します。

> RunWorkerCompletedが実行されていないというのはどのように判断しましたか?
usingの部分をすべてコメントアウトし実行すると、RunWorkerCompleted内のMessageBox.Show()が実行されたためです。
コメントアウトしないまま実行してキャンセルを押すと、逐次処理は終了するのですが、bgWorkerが開放されません。
そのため、もういちど呼び出そうるとするとbgWorkerがビジー状態であると怒られます。

> 実はキャンセル時はキャンセルしたあと即座にフォームを閉じてるとか、そんなことあったりします
下記ソースに載せた通り、bgWorker.CancelAsync();を行っているだけです。

>StreamReader.EndOfStream で末端チェックしているのはいいですが肝心の読み込み処理がないですね・・・
実際には読み込んで、Formのテキストエリアに逐次表示しています。


実際のところどこか勘違いしていると思うのですが、怪しいところはどのあたりなのでしょうか。
何度も申し訳ありませんが、よろしくお願いします。
ソースは事情により一部伏せ、抜いている部分がありますがご容赦下さい。
不足があれば追加いたします。

        private void cancel_Click(object sender, EventArgs e)
        {
            bgWorker.CancelAsync();
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.WriteLine("thread start");
            BackgroundWorker worker = (BackgroundWorker)sender;

            using (StreamReader reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }

                    string str_abc = reader.ReadLine().ToString();
                    Console.WriteLine(str_abc);
                    System.Threading.Thread.Sleep(500);
                }
            }
        }

        private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Console.WriteLine("bgWorker_RunWorkerCompleted");
            if (e.Cancelled)
            {
                MessageBox.Show("キャンセルされました");
                // この場合にはe.Resultにはアクセスできない
            }
            else
            {
                // 処理結果の表示
                MessageBox.Show("正常に完了");
            }
        }

引用返信 編集キー/
■48851 / inTopicNo.8)  Re[7]: bgWorkerにおけるusingのbreak
□投稿者/ みきぬ (864回)-(2010/04/15(Thu) 13:59:05)
質問と関係あるかわかんないけど、

No48850 (Jem さん) に返信
> >StreamReader.EndOfStream で末端チェックしているのはいいですが肝心の読み込み処理がないですね・・・
> 実際には読み込んで、Formのテキストエリアに逐次表示しています。

これを DoWork イベントハンドラの中でやるのは注意してください。
DoWork イベントハンドラは、UIスレッドとは別のスレッドで実行されるので。

Control.Invoke を使うか、ProgressChanged イベントハンドラ内で行うかしてください。
引用返信 編集キー/
■48853 / inTopicNo.9)  Re[8]: bgWorkerにおけるusingのbreak
□投稿者/ Jem (6回)-(2010/04/15(Thu) 14:02:46)
No48851 (みきぬ さん) に返信

ご指摘ありがとうございます。
実際にはReportProgressし、ProgressChanged内でForm内を書き換えています。

> 質問と関係あるかわかんないけど、
>
> ■No48850 (Jem さん) に返信
>>>StreamReader.EndOfStream で末端チェックしているのはいいですが肝心の読み込み処理がないですね・・・
>>実際には読み込んで、Formのテキストエリアに逐次表示しています。
>
> これを DoWork イベントハンドラの中でやるのは注意してください。
> DoWork イベントハンドラは、UIスレッドとは別のスレッドで実行されるので。
>
> Control.Invoke を使うか、ProgressChanged イベントハンドラ内で行うかしてください。
引用返信 編集キー/
■48855 / inTopicNo.10)  Re[7]: bgWorkerにおけるusingのbreak
□投稿者/ よねKEN (469回)-(2010/04/15(Thu) 14:07:07)
2010/04/15(Thu) 14:11:22 編集(投稿者)
No48850 (Jem さん) に返信
確認事項へのご返答ありがとうございます。

> ソースは事情により一部伏せ、抜いている部分がありますがご容赦下さい。

例えば、その中の処理で止まっているということはないでしょうか。

Textで実際にFormに描画されるまで
http://bbs.wankuma.com/index.cgi?mode=al2&namber=48812
の関連質問ですよね?

例えば、ReadLineメソッドで止まっていたり・・・ということはないかなと気になります。

提示のコードの「Console.WriteLine(str_abc);」の箇所による
表示は進んでいるのでしょうか?


> 実際のところどこか勘違いしていると思うのですが、怪しいところはどのあたりなのでしょうか。

提示のソースコードの範囲では特に怪しいところはありませんでした。
以下のように検証しました。

(1) 新規プロジェクトを作成 (VS2008、WinXP SP2、Windowsアプリ)
(2) start/cancelとしてButtonを配置
(3) bgWorkerとしてBackgroundWorkerを配置
(4) デザイナでbgWorkerのWorkerSupportsCancellationプロパティをTrueに設定。
(5) 各ボタンのClickイベント、bgWorkerのDoWorkイベント、RunWorkerCompletedイベントと
  ハンドラの紐付けもデザイナで行いました。
(6) 検証のため、private変数でstreamを追加。startボタンのClickイベントでMemoryStreamを使って
  複数行のテキストに関連付けています。
(7) 2回実行してみて、キャンセルせずに待って"正常に完了"のメッセージ、
  キャンセルを実行して"キャンセルされました"のメッセージ、を確認しました。

'-- 記述したコード --
using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        // 検証のための追加コード
        private Stream stream;

        public Form1()
        {
            InitializeComponent();
        }

        private void start_Click(object sender, EventArgs e)
        {
            // 検証のための追加コード
            string text = "";
            for (int i = 0; i < 10; i++)
            {
                text += i.ToString("0000") + ":あいう\n"; 
            }
            stream = new MemoryStream(Encoding.UTF8.GetBytes(text));
            bgWorker.RunWorkerAsync();
        }

        private void cancel_Click(object sender, EventArgs e)
        {
            bgWorker.CancelAsync();
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.WriteLine("thread start");
            BackgroundWorker worker = (BackgroundWorker)sender;

            using (StreamReader reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }

                    string str_abc = reader.ReadLine().ToString();
                    Console.WriteLine(str_abc);
                    System.Threading.Thread.Sleep(500);
                }
            }
        }

        private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Console.WriteLine("bgWorker_RunWorkerCompleted");
            if (e.Cancelled)
            {
                MessageBox.Show("キャンセルされました");
                // この場合にはe.Resultにはアクセスできない
            }
            else
            {
                // 処理結果の表示
                MessageBox.Show("正常に完了");
            }
        }
    }
}

引用返信 編集キー/
■48856 / inTopicNo.11)  Re[9]: bgWorkerにおけるusingのbreak
□投稿者/ 魔界の仮面弁士 (1622回)-(2010/04/15(Thu) 14:12:46)
No48853 (Jem さん) に返信
>>> 実際には読み込んで、Formのテキストエリアに逐次表示しています。
> 実際にはReportProgressし、ProgressChanged内でForm内を書き換えています。

伏せたい部分もあるでしょうから、『実際』のコードと違うのは仕方ないとして、
そもそも、「今回提示しているソース」を新規プロジェクトに貼りつけて検証した場合に、
問題が再現するかどうかを確認されていますでしょうか?

もし、それで再現しないのであれば、提示した情報からでは答えようがありませんので、
検証コードと実際のコードとの違いを洗い出してみて下さい。

# 今のコードだと、たとえば stream がどこから得たものかなどの情報がありませんので、
# 提示されたコードだけでは、実際の動作を検証できるようにはなっていません。
引用返信 編集キー/
■48857 / inTopicNo.12)  Re[8]: bgWorkerにおけるusingのbreak
□投稿者/ みきぬ (865回)-(2010/04/15(Thu) 14:13:49)
> 例えば、ReadLineメソッドで止まっていたり・・・ということはないかなと気になります。
>
> 提示のコードの「Console.WriteLine(str_abc);」の箇所による
> 表示は進んでいるのでしょうか?
>
それに加えて、メソッドの終了直前にもログを出して、
本当にそこを通るかどうか確認したほうがいいですね。
引用返信 編集キー/
■48858 / inTopicNo.13)  Re[8]: bgWorkerにおけるusingのbreak
□投稿者/ Jem (7回)-(2010/04/15(Thu) 14:19:01)
No48855 (よねKEN さん) に返信
はい、以前のTextの質問に続いたものです。

> 提示のコードの「Console.WriteLine(str_abc);」の箇所による
> 表示は進んでいるのでしょうか?
正しく表示されています。

キャンセルボタンを押し、CancellationPendingがtrueとなり、breakしているのは確認できます。
ただし、下記のソースでいうと、"after while"の出力後に、"after using"の出力に到達していません。
"after while"を出力し、サスペンドしたような状態に入っています。
DoWorkが正しく終了していない挙動の気がします。

            using (StreamReader reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    /*********/
                }

                Console.WriteLine("after while");
            }
            Console.WriteLine("after using");
            e.Result = "スレッド処理終了";

> 2010/04/15(Thu) 14:07:43 編集(投稿者)
> 
> ■No48850 (Jem さん) に返信
> 確認事項へのご返答ありがとうございます。
> 
>>ソースは事情により一部伏せ、抜いている部分がありますがご容赦下さい。
> 
> 例えば、その中の処理で止まっているということはないでしょうか。
> 
> Textで実際にFormに描画されるまで
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=48812
> の関連質問ですよね?
> 
> 例えば、ReadLineメソッドで止まっていたり・・・ということはないかなと気になります。
> 
> 提示のコードの「Console.WriteLine(str_abc);」の箇所による
> 表示は進んでいるのでしょうか?
> 
> 
>>実際のところどこか勘違いしていると思うのですが、怪しいところはどのあたりなのでしょうか。
> 
> 提示のソースコードの範囲では特に怪しいところはありませんでした。
> 以下のように検証しました。
> 
> (1) 新規プロジェクトを作成
> (2) start/cancelとしてButtonを配置
> (3) bgWorkerとしてBackgroundWorkerを配置
> (2) デザイナでbgWorkerのWorkerSupportsCancellationプロパティをTrueに設定。
> (3) 各ボタンのClickイベント、bgWorkerのDoWorkイベント、RunWorkerCompletedイベントと
>   ハンドラの紐付けもデザイナで行いました。
> (4) 検証のため、private変数でstreamを追加。startボタンのClickイベントでMemoryStreamを使って
>   複数行のテキストに関連付けています。
> (5) 2回実行して、キャンセルせずに待って"正常に完了"のメッセージを、
>   キャンセルを実行して"キャンセルされました"のメッセージを確認しました。
> 
> '-- 記述したコード --
> using System;
> using System.ComponentModel;
> using System.Text;
> using System.Windows.Forms;
> using System.IO;
> 
> namespace WindowsFormsApplication1
> {
>     public partial class Form1 : Form
>     {
>         // 検証のための追加コード
>         private Stream stream;
> 
>         public Form1()
>         {
>             InitializeComponent();
>         }
> 
>         private void start_Click(object sender, EventArgs e)
>         {
>             // 検証のための追加コード
>             string text = "";
>             for (int i = 0; i < 10; i++)
>             {
>                 text += i.ToString("0000") + ":あいう\n"; 
>             }
>             stream = new MemoryStream(Encoding.UTF8.GetBytes(text));
>             bgWorker.RunWorkerAsync();
>         }
> 
>         private void cancel_Click(object sender, EventArgs e)
>         {
>             bgWorker.CancelAsync();
>         }
> 
>         private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
>         {
>             Console.WriteLine("thread start");
>             BackgroundWorker worker = (BackgroundWorker)sender;
> 
>             using (StreamReader reader = new StreamReader(stream))
>             {
>                 while (!reader.EndOfStream)
>                 {
>                     if (worker.CancellationPending)
>                     {
>                         e.Cancel = true;
>                         break;
>                     }
> 
>                     string str_abc = reader.ReadLine().ToString();
>                     Console.WriteLine(str_abc);
>                     System.Threading.Thread.Sleep(500);
>                 }
>             }
>         }
> 
>         private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
>         {
>             Console.WriteLine("bgWorker_RunWorkerCompleted");
>             if (e.Cancelled)
>             {
>                 MessageBox.Show("キャンセルされました");
>                 // この場合にはe.Resultにはアクセスできない
>             }
>             else
>             {
>                 // 処理結果の表示
>                 MessageBox.Show("正常に完了");
>             }
>         }
>     }
> }
> 

引用返信 編集キー/
■48864 / inTopicNo.14)  Re[9]: bgWorkerにおけるusingのbreak
□投稿者/ よねKEN (470回)-(2010/04/15(Thu) 15:21:00)
No48858 (Jem さん) に返信
> キャンセルボタンを押し、CancellationPendingがtrueとなり、breakしているのは確認できます。
> ただし、下記のソースでいうと、"after while"の出力後に、"after using"の出力に到達していません。
> "after while"を出力し、サスペンドしたような状態に入っています。

であれば、その間で何かが起こっているのでしょう。

> using (StreamReader reader = new StreamReader(stream))
> {
> while (!reader.EndOfStream)
> {
> /*********/
> }
>
> Console.WriteLine("after while");
> }
> Console.WriteLine("after using");
> e.Result = "スレッド処理終了";

この通りのコードの形で"after using"が表示されないのであれば、
readerのDisposeメソッド(というかそのstream(何Streamか知りませんが)のDiposeメソッド
(一般的な作りのStream派生クラスなら、通常はCloseメソッドとイコール))で例外が発生しているのでは?

usingブロックでは最後にDiposeメソッドが呼ばれます。
対象のstreamで実際にDiposeメソッド呼出時に例外が発生することがあるのかはそのクラス次第ですが、

try
{
using { 〜 }
} catch (Exception ex)
{
//例外の内容をいろいろ表示
}

のようなコードにしてusingブロックで起きる例外をキャッチしてみると何かわかるかもしれません。

引用返信 編集キー/
■48865 / inTopicNo.15)  Re[10]: bgWorkerにおけるusingのbreak
□投稿者/ みきぬ (867回)-(2010/04/15(Thu) 15:33:15)
DoWork イベントハンドラ内で例外が発生していても、RunWorkerCompleted イベントは発生するはず。


なので、Dispose できなくて固まっていると予想してみた。
引用返信 編集キー/
■48866 / inTopicNo.16)  Re[10]: bgWorkerにおけるusingのbreak
□投稿者/ Jem (8回)-(2010/04/15(Thu) 15:37:21)
No48864 (よねKEN さん) に返信

原因がわかりました。
このStreamはHttpWebRequestで得られたストリームから生成していました。
キャンセルを検知したときに、request.Abort();がなかったのが原因でした。
リクエストがサスペンドしていたようです。

明らかに私の提供情報不足でした…。今後気を付けたいと思います。
回答してくださった皆様、本当にありがとうございました。

> ■No48858 (Jem さん) に返信
>>キャンセルボタンを押し、CancellationPendingがtrueとなり、breakしているのは確認できます。
>>ただし、下記のソースでいうと、"after while"の出力後に、"after using"の出力に到達していません。
>>"after while"を出力し、サスペンドしたような状態に入っています。
> 
> であれば、その間で何かが起こっているのでしょう。
> 
>>            using (StreamReader reader = new StreamReader(stream))
>>            {
>>                while (!reader.EndOfStream)
>>                {
>>                    /*********/
>>                }
>>
>>                Console.WriteLine("after while");
>>            }
>>            Console.WriteLine("after using");
>>            e.Result = "スレッド処理終了";
> 
> この通りのコードの形で"after using"が表示されないのであれば、
> readerのDisposeメソッド(というかそのstream(何Streamか知りませんが)のDiposeメソッド
> (一般的な作りのStream派生クラスなら、通常はCloseメソッドとイコール))で例外が発生しているのでは?
> 
> usingブロックでは最後にDiposeメソッドが呼ばれます。
> 対象のstreamで実際にDiposeメソッド呼出時に例外が発生することがあるのかはそのクラス次第ですが、
> 
> try
> {
>    using {   〜   }
> } catch (Exception ex)
> {
>     //例外の内容をいろいろ表示
> }
> 
> のようなコードにしてusingブロックで起きる例外をキャッチしてみると何かわかるかもしれません。
> 

解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -