![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?8acaa2e)
Microsoft visual C#2005でスレッドを使用したプログラムを行なっているのですが,意図した動作を行えません.
意図する動作は,連番で複数の画像を持つ二つのフォルダ(0,1とします)から画像をリストに読み込み,フォルダ0読み込み→フォルダ0内の画像を順に続けて表示(この間にフォルダ1の読み込み)→3秒置いて→フォルダ1内の画像を順に続けて表示です.
//再生ボタン
private void button_Click(object sender, EventArgs e)
{
//フォルダ0読込
directory = directories[0];
Read = new Thread(new ThreadStart(read_image));
Read.Start();
if(now_loading == true)
{
Read.join();
}
//フォルダ0表示
Showing1 = new Thread(new ThreadStart(Show));
Showing1.Start();
//フォルダ1読込
directory = directories[1];
Reads = new Thread(new ThreadStart(read_images));
Reads.Start();
}
if(now_showing == true)
{
Showing1.Join();
}
if(now_showing == true)
{
Reads.Join();
}
//フォルダ1表示
Showing2 = new Thread(new ThreadStart(Show));
Showing2.Start();
}
//動画表示
private void Show()
{
Stopwatch sw = new Stopwatch();
//リストに入っているファイルの数をfile_numbersに入れる
file_numbers = img.Count;
//1枚目を表示
pictureBox1.Image = img[0];
//フレーム番号のリセット
now_show = 1;
//時間計測:開始
sw.Start();
while (now_show < file_numbers)
{
if (33 <= sw.ElapsedMilliseconds)//一枚の表示時間が33ミリ秒以上になったら次の画像を表示
{
//前フレームを消去
img[0].Dispose();
img.RemoveAt(0);
//画像を表示
pictureBox1.Image = img[0];
//カウントを進める
now_show++;
//時間計測再スタート
sw.Reset();
sw.Start();
}
}
//時間計測:停止
sw.Stop();
//最終フレームを消去
pictureBox1.Image = null;
img[0].Dispose();
img.RemoveAt(0);
Thread.Sleep(3000);//3秒待機
}
//読込
private void read_images()
{
int read_numbers = Directory.GetFiles(directory).Length;
now_loading = true;
for (int i = 0; i < read_numbers; i++)
{
img.Add(Image.FromFile(String.Format("{0}\\{1:000}.jpg", directory, i)));
}
now_loading = false;
}
//初回読込
private void read_image()
{
now_loading = true;
//フォルダ内のファイル数の取得
file_numbers = Directory.GetFiles(directory).Length;
//画像ファイルを読み込む
img = new List<Image>();
for (int i = 0; i < file_numbers; i++)//ファイル数の数
{
img.Add(Image.FromFile(String.Format("{0}\\{1:000}.jpg", directory, i)));
}
now_loading = false;
}
joinでスレッドの終了を待つということなので,B表示スレッドを開始する前に A表示スレッド.join を置けばよいと考えたのですが,タイマーを配置して見たところA表示のスレッドのjoinを待つ前にB表示のスレッドが始まってしまっているようです.(Show内の始めと終わりの部分でテキスト表示すると,フォルダ1の再生後にフォルダ0のShowスレッドが終了していました)
また,各画像フォルダの再生時間もタイマで図るとほぼ指定した通りなのですが自分の時計で計測すると画像500枚で2秒程度短くなってしまいます.
joinを使っている時点で表示スレッドを関数にした方が良いのかもしれませんが,何故思うように動かないのか知りたいです.
アドバイス頂けると嬉しいです.
No.1ベストアンサー
- 回答日時:
>A表示のスレッドのjoinを待つ前にB表示のスレッドが始まってしまっているようです.
>Read.Start();
>if(now_loading == true)
この間にスレッド切り替えが発生して、read_image()のnow_loading = trueが処理される。
という保証は無いかと思いますが、どうなんでしょうかね?
Thread.Sleep()でスレッド切り替えの機会を入れれば…というのはありますが、それでも確実ではないでしょう。
# 何より、イベントハンドラ内でそういう待ちは入れるべきではない…かと。
now_loadingとかnow_showingとかはスレッドセーフなオブジェクトなんですか?
>if(now_loading == true)
で判定した直後にスレッド切り替えが発生してnow_loadingの値が変わる…とかいうことはないのでしょうか?
# 該当処理中に「now_loading」が変化しないから最適化で実効コードが消える。
# なんてことはC#であるんでしょうかね?
回答ありがとうございます.
【訂正】
フォルダ1の前の
if(now_showing == true)
{
Reads.Join();
}
のnow_showingはnow_loadingの間違いです.失礼しました.
>>Read.Start();
>>if(now_loading == true)
>この間にスレッド切り替えが発生して、read_image()のnow_loading = trueが処理される。
>という保証は無いかと思いますが、どうなんでしょうかね?
ご指摘頂いたとおり,確認してみたところ先にif文の方が判定される場合があり,その時にスレッドが終了していないままjoinもスルーされていたようです.
単純にif(now_loading == true)の下りを削除し,joinは必ず実行されるようにしたところ,出力でチェックする限りは最初のフォルダの再生終了前にBが再生され始めるということは無くなりました.
また,再生時間も実測時間と同じになりました.
ただ,Reads.Join();の部分でInbaridOperationExeceptionはハンドルされませんでしたとエラーが出たのですが,対象とするスレッドが終了しているのが理由と見てもいいのでしょうか.joinは対象とするスレッドが終了している場合,特に何もエラーは出ないと考えていたのですが.
この部分のみ,if(now_loading==true)で囲んでみたりもしたのですが,読込スレッド内のnow_loadingのtrue(もしくはfalse)切り替えとかぶってしまうのか,同様のエラーが出ました.
また,読み込みが終わってから表示を始めているのですが,一つ目のフォルダ再生の際にどうしてもカクカクとした動きになってしまうのですが,メモリを見る限り不足している様子はないのですが,解決策はあるのでしょうか….
joinが何故スルーされるか分からなかったので,原因が分かって良かったです.有難うございます.
now_loadingをスレッドセーフにすれば良いのかとdalegate型を使おうと一から調べているのですが,理解が遅くもう少し掛かりそうです.
お気づきのところがあれば,引き続きご指摘頂けると嬉しいです.
No.2
- 回答日時:
C#自体たいして経験があるワケではないのですが…
# しかも使っているのは.NET Framework 4の方。
# 自宅PCにインストールしてあるVS2005StdのC#は使っていないし…。
>ただ,Reads.Join();の部分でInbaridOperationExeceptionはハンドルされませんでしたとエラーが出たのですが,対象とするスレッドが終了しているのが理由と見てもいいのでしょうか.
たぶん、別…ではないですかね。
スレッド内の処理のどれかが例外出しているんじゃないかと思われますが……。
>joinは対象とするスレッドが終了している場合,特に何もエラーは出ないと考えていたのですが.
ヘルプだとそう書かれてますね。
タイミングなんですかねぇ……。
ところでInbaridOperationExeceptionの例外にはどんなメッセージついていましたか?
>>ところでInbaridOperationExeceptionの例外にはどんなメッセージついていましたか?
試しに,if(now_loading==true)の下りを全て削除し,呼び出すスレッドの名前を全て統一してみたところ,InvaridOperationExeceptionは出なくなりました.以降そのまま進めているのでメッセージは確認できませんでした.ただ,10回程度回しただけなので運が良かっただけかもしれません….
Joinメソッドは対象とするスレッドが終了している場合は問題ないようですが,ThreadState.Unstarted 状態のスレッドで Join を呼び出すことはできないようなのでそれが原因かもと思っています.
表示が想定どおりに行かないので,Thread.Abortを取り入れたところ一つ目のフォルダは問題なく表示されるようになったのですが,やはり二つ目が想定表示時間よりも短くなるようです.
Joinの挙動についてはおかげで解決しましたので,Abortは新たに質問し直させて頂きました.一旦この質問版は閉じさせて頂きます.
回答有難うございました.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript アップロードファイルの種類によって処理を分岐させたいのですが書き方が分からずアドバイスお願いします 4 2023/06/17 19:12
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- PHP ここでの ②if($su_d<>"")の比較演算子 を使う理由は 1 2022/03/26 02:33
- その他(プログラミング・Web制作) pythonのグローバル変数 2 2022/11/25 18:02
- JavaScript 画像の表示位置 3 2022/12/23 08:25
- PHP htmlspecialcharsが機能していないです。 バグですか? 1 2022/04/05 01:22
- Perl RSSにdiv,ul classを付けたいのですがどのようにつけるのかわからないです 2 2022/03/28 01:53
- PHP imageフォルダに、画像をリサイズして保存する時のファイル名を変更したい 1 2023/05/30 11:39
- C言語・C++・C# C#テキストボックスの文字を配列にいれてその後表示する 4 2022/07/17 04:47
- Excel(エクセル) エクセル VBA For Next 繰り返しの書き方を教えてください 6 2022/09/01 14:11
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Windows Vista、7でのマルチス...
-
KENT "Web Patio" のトピックス...
-
c#のメソッドjoinが機能しない
-
メインダイアログが最背面に表...
-
ユーザーインターフェイスの一...
-
【C++】boost threadについて
-
Macターミナルで実行中のプログ...
-
タスクマネージャーのプロセス...
-
C言語で、メモリを解放しないで...
-
explorer.exeが異様にメモリを食う
-
家電製品の電力周波数を変える機械
-
メモリアロケーション異常の発...
-
VBA kernel32 の意味
-
C++からCへのソース変換について
-
ストール監視の監視方法
-
C++でCtrl+Cを無効化したい
-
非表示になったエクセルは?
-
Mac 乗数の入力方法
-
指定したフォルダーを最前面表...
-
Excel VBA データ削除の高速化
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
WaitForSingleObjectの使い方に...
-
VC++スレッドの正しい終了のさ...
-
スレッドの監視方法について
-
スレッドの安全な終了のさせ方
-
Windows上で、シグナル(SIGTERM...
-
マルチスレッドプログラミング...
-
スレッドの終了の仕方
-
スレッドにて同一メモリの書き...
-
VB2005 シリアル通信のClose処理
-
スレッドの終了はどうやるんで...
-
スレッドでWM_TIMERを受け取れない
-
同一スレッドで、ロックをかけ...
-
マルチスレッドのスレッド数を...
-
pthread_cond_wait 取りこぼし?
-
MFC通信プログラムマルチスレッ...
-
LinuxでDoEvents()同等機能
-
WaitForMultipleObjectのイベン...
-
【VC++6.0(MFC)】スレッドの呼...
-
待機関数(WaitForMultipleObjec...
-
CWnd::OnTimerのスレッドの取得
おすすめ情報