質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

4回答

10177閲覧

C# BackgroundWorker 処理が実行されなくなる現象

TEC_S

総合スコア79

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2017/04/07 08:09

編集2017/04/21 02:22

###前提・実現したいこと
BackgroundWorkerを使い、プログレスバーを作っています。
プログレスバー呼び出し先のダイアログから、複数回プログレスバーを呼び出す処理を作りたいと考えています。(プログレスバーは1つで、プログレスバー内で複数の処理がある)

プログレスバー内のスレッドが2回目の呼び出し以降、動かなくて困っています。
デバック方法や、進め方について、アドバイスを頂きたいです。
宜しくお願い致します。

###発生している問題・エラーメッセージ
特にエラーメッセージは出ていません。(Windowsイベントビューアー含み)
現在困っていることは、同じダイアログから2回目以降、プログレスバーを呼び出すと、バックグランドワーカーのスレッドが動かずに、処理が終わってしまっています。

厄介なことに、デバッカでは症状が発生せず、デバッカが入っていないPCにて動作をさせると、症状が出ます。処理の先頭にLogを出力しており、そのLogが確認出来ない事から、処理が実行されずに、終了されているものと考えています。暫くすると、同じことをやっているのに、処理がされるようになり、Logも正常に書き込まれます。

下記ソースコードに記載させて頂いた「スレッド開始」が記載ず、終了しています。

###該当のソースコード

呼び出し側

C#

1ProgressForm pr = new ProgressForm(); 2pr.progress_Type = (int)ProgressForm.progressModeType.SETTING_MANU;//プログレスバーのモード指定 3pr.ShowDialog();

プログレスバー側

C#

1 private void timer1_Tick(object sender, EventArgs e) 2{ 3 if (start_copy) 4 { 5 start_copy = false; 6 7 // バックグラウンドワーカーの設定. 8 WorkerCopy = new System.ComponentModel.BackgroundWorker(); // オブジェクト作成. 9 WorkerCopy.DoWork += new System.ComponentModel.DoWorkEventHandler(Worker_DoCopyWork); // メインの処理. 10 WorkerCopy.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(Worker_CopyProgressChanged); // プログレスバーカウントアップ. 11 WorkerCopy.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(Worker_CopyWorkerCompleted); // 終了処理. 12 13 WorkerCopy.WorkerReportsProgress = true; // 進捗状況の確認. 14 WorkerCopy.RunWorkerAsync(); // バックグラウンドワーカースタート. 15 } 16} 17 18 19void Worker_DoCopyWork(object sender, System.ComponentModel.DoWorkEventArgs e) 20{ 21 log.writing(progGetLogPath, " ********** スレッド開始 ********** "); 22 23 //時間のかかる処理 24 25 log.writing(progGetLogPath, " ********** スレッド終了 ********** "); 26} 27 28void Worker_CopyWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) 29{ 30 WorkerCopy.Dispose(); 31 32 // エラーメッセージ等の終了時の処理 33} 34

###試したこと
WorkerCopy.Dispose()を「Worker_CopyWorkerCompleted」に追加してみましたが、効果はありませんでした。。
また、プログレスバーが閉じられる時に、リソースは全て解放されると認識していましたので、呼び出し側のダイアログを終了させる事や、pr.Dispose()等での開放もしてみましたが、効果がありませんでした。

ご指摘を受け調査した所、Log出力の為のLogクラスに問題がある事が分かりました。上記記載したクラスのどれでもありませんでした。

下記がLogクラス内のコードなのですが、logFileがアクセス出来ない状態になっている場合があります。しかし、、書き込み後にしっかりと開放していると思うのですが・・・下記書かたが悪いのでしょうか。

C#

1class AddLog 2{ 3 public void writing(string logFile, string msg) 4 { 5 if (log_path == "") 6 return; 7 8 //現在時刻 9 DateTime dt = DateTime.Now; 10 11 //書き込み 12 try 13 { 14 using (StreamWriter sw = new StreamWriter(logFile, true, Encoding.GetEncoding("shift_jis"))) 15 { 16 string str = dt.ToString("[yyyy-MM-dd-HHmmss]") + " " + msg + "\r\n"; 17 sw.Write(str); 18 sw.Close(); 19 } 20 21 //StreamWriter sw = new StreamWriter(logFile, true, Encoding.GetEncoding("shift_jis")); 22 //string str = dt.ToString("[yyyy-MM-dd-HHmmss]") + " " + msg + "\r\n"; 23 //sw.Write(str); 24 //sw.Close(); 25 } 26 catch (Exception ex) 27 { 28 System.Windows.Forms.MessageBox.Show(ex.Message.ToString()); 29 Console.WriteLine(ex.Message.ToString()); 30 } 31} 32

###補足情報(言語/FW/ツール等のバージョンなど)
開発環境:Visual Studio2015
開発環境OS:Windows7 64bit

発生環境:Windows8.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2017/04/08 07:14

不具合が再現する状態を保ちながらソースを削って小さくしていき、再現する最小のソースを作ってみたらどうでしょうか? その過程で自己解決できればよし、できなくてもこちらで問題を調べることができるようになります。
TEC_S

2017/04/21 02:15

ご指摘、ありがとうございます。調査した所、記載したクラスではなく、Logを出力するためのクラスに問題がありそうです。追記させて頂きます。
guest

回答4

0

AddLog が非同期対応していません。あるスレッドがログに書き込みをしている最中に別のスレッドが書き込もうとすると例外が発生すると思います。

ログに書き込む場合は直接書き込むのではなく、書き込みたいデータを待ち行列に追加し、それを順々に処理して行くのが良いのではないかと思います。

あと、StreamWriter の Close メソッドを明示的に呼んでいますが、これは using で処理されますので無用です。

投稿2017/04/21 02:41

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2017/04/21 05:59

回答ありがとうございます。 非同期対応していないという事、了解しました。 処理としては、アクセス可能か確認 → 書き込み (不可なら退避し随時書き込み)という処理をAddLogクラスに持たせれば良いという事ですね。 やってみます。
guest

0

こんにちは。

厄介なことに、デバッカでは症状が発生せず、デバッカが入っていないPCにて動作をさせると、症状が出ます。

厄介ですね。
このような時は、ログをどんどん入れていくしかないと思います。
Workerスレッドが起動していないのであれば、起動するまでの処理がどこかで中断している筈です。
ProgressForm()のnewから、Workerスレッドの先頭までの要所要所でログを出して、どこで中断しているのか見つけることができると良いと思います。

概ね決まったところで中断していれば良いのですが、もしも、毎回、異なる場所で中断しているとなかなか頭痛いです。もしも、そうなっていたら、何か排他制御に失敗してデータを破壊していることなどが疑われます。

投稿2017/04/07 08:59

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2017/04/21 02:25

ご回答が漏れており、申し訳ありません。 調査した所、まさかのLog出力の為のLogクラスに問題がある事が分かりました。Logファイルへのアクセス権が無いとExceptionが発生していました。 明示的に開放出来るよう工夫してみたつもりですが・・・書き方、もしくはLogクラスの呼び出し方に問題があるのでしょうか。。  ※上記「試したこと」にソースコード追記しました。 宜しくお願い致します。
Chironian

2017/04/21 04:10

与えているログ・ファイルを相対パスで指定していないでしょうか? デバッガで実行した時とそうでない時で、カレント・フォルダが異なるため、直接実行時のフォルダが書き込み権限のないフォルダになっている可能性はあると思います。
guest

0

start_copy が boolean でかつ初期値が true と仮定しまして。

1回目に

start_copy = false;

としたから、2回目以降

if (start_copy)

に入らないだけでは?

投稿2017/04/07 08:57

workaholist

総合スコア559

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2017/04/21 02:26

ご回答、ありがとうございます。 start_copyには、入っていました。
guest

0

BackgroundWorker は、APIが一新された、UWPでは、存在しないもので、互換性のために残っているのにすぎません。過去の遺物です。
Taskを使いましょう。

これを参考にするといいと思います。
http://www.atmarkit.co.jp/ait/articles/1512/02/news019.html

投稿2017/04/07 08:52

kiichi54321

総合スコア1984

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2017/04/21 02:27

Taskの件、ありがとうございました。 今後、Taskを使っていこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問