tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルマルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5835
投稿日: 2007/07/15(Sun) 05:34
投稿者ポン太
こんにちは。
どうしてもわからないことがありまして書き込みをさせて頂きました。
よろしくおねがいします。

For Nextなどの繰り返しの中で
スレッドを何度も実行したいのですが、
どのようにしたら良いでしょうか。

現在は下記のようになっているのですが、
2回目のt.Start()のところでエラーになってしまいます。

Public A As String

Sub ShoriA()
Dim t As New System......Start(AddressOf ShoriB))
For i=0 to 1000
ここで変数Aの中を設定
t.Start()
ShoriBが終了するまで待機
Next
End Sub

Sub ShoriB()
変数Aを使って処理を行う
End Sub

このようになっているのですが、どのようにしたら
エラーにならずに繰り返しスレッドを実行することが出来るでしょうか。
大変恐れ入りますがご教授頂けましたら幸いです。

[ツリー表示へ]
タイトルRe: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5840
投稿日: 2007/07/16(Mon) 13:47
投稿者魔界の仮面弁士
> ShoriBが終了するまで待機
毎回、スレッドを待機させるなら、そもそもスレッドを分ける意味は無いと思いますよ。
ShoriB そのものを Call するだけで済みますよね。たとえば、こんなイメージ。
----
 ''Public A As String  'これは使わない
----
 For i = 0 To 1000
  x = 変数xを設定
  Call ShortB(x)
 Next
----
 Sub ShoriB(ByVal x As String)
  '(変数Aのかわりに)xを使って処理を行う
 End Sub
----

[ツリー表示へ]
タイトルRe^2: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5841
投稿日: 2007/07/17(Tue) 01:44
投稿者ポン太
魔界の仮面弁士様お返事ありがとうございます。

ご回答頂いたようにするとフォームがロックしてしまうため、
やはりスレッドを分けたいです。
ファイルをアップロードしたりダウンロードしたりするソフトなので、
私の出来る方法だとApplication.Doevents()を入れる隙間がありません。
(System.Net.WebClientを使っております)
--------------------
For i = 0 To 1000
  x = 変数xを設定
'処理Bをここで実行
 Next
--------------------
この様にして一つにまとめてしまって別スレッドに入れれば良いのかと思うのですが
一連の処理が終わった後で、別の設定でまたFor i = 0 To 1000を
実行したいことがあるので、やはりスレッドを再度実行したいです。
全部をリセットしたりするようなことはできないものでしょうか?

何か方法がございましたらご回答を頂けると助かります。
よろしくお願い致します。

[ツリー表示へ]
タイトルRe^3: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5842
投稿日: 2007/07/17(Tue) 09:48
投稿者よねKEN
WebClientを使ってダウンロードやアップロードをしているということはわかりましたが、
アプリケーションでやりたいことをもう少し詳しく書いていただいた方がよいと思います。
スレッドがうんぬんとかいう技術的な実現方法の前に、アプリの機能概要の説明が欲しいですね。
#なんとなくやりたいことはわかる気もするんですが、ソースコード例とがいまいち繋がりません。

> 魔界の仮面弁士様お返事ありがとうございます。
>
> ご回答頂いたようにするとフォームがロックしてしまうため、
> やはりスレッドを分けたいです。

ぽん太さんの最初の投稿にあるソースコードのイメージだと
スレッドを使う意味がなく、魔界の仮面弁士さんのシングルスレッドの
サンプルと結果的に同じことをやっていることになります。

(最初の投稿のソース例の一部)
>t.Start()
>ShoriBが終了するまで待機
↑ここで待機するとあるので、マルチスレッドにならない。

> ファイルをアップロードしたりダウンロードしたりするソフトなので、
> 私の出来る方法だとApplication.Doevents()を入れる隙間がありません。
> (System.Net.WebClientを使っております)

バージョンはVB2005(.NET Framework2.0)でしょうか?
そうであれば、WebClientのDownloadFileAsync、UploadFileAsyncなどの
〜Asyncメソッドがありますので、スレッドを使う必要はたぶんありません。

[ツリー表示へ]
タイトルRe^4: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5844
投稿日: 2007/07/17(Tue) 13:41
投稿者ポン太
お返事ありがとうございます。

バージョンを書かずに申し訳ありません。
VB.NET Framework1.1になります。
その為、Asyncというものが使えないので、WebClientの方法を採用しております。

やはりこの方法だとアップロード、ダウンロードが開始されると一切のフォームへのアクセスが
止まってしまいます。
For Next の数がUL、DLのファイルの数だとして、
UL、DLが一つ完了したら、一旦そこで待機させて、
続行か中止かを判断できるようにチェックボックスなどで
指定したいので、フォームを操作できるようにしておきたいのです。
(DL、UL自体の中断は考えておりません)


>t.Start()
>ShoriBが終了するまで待機
↑の部分はApplication.DoEvents()を挟んで
UL、DLスレッドとの同期の為にPulic変数(Status)で判断しています。

Data=wc.Download.data(a)
Status=True

Sub Button1_Click
Do Until Status = False
Application.DoEvents()

・その他の判断、処理

Loop
End Sub

やろうとしていることはあまり一般的ではないのでしょうか??

[ツリー表示へ]
タイトルRe^5: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5846
投稿日: 2007/07/17(Tue) 13:58
投稿者ポン太
間違いがあり分かりにくい書き方になっているかと思いますので、
少し修正させてください。

Public A as Boolen

Sub Download() ←別スレッドのプロシージャ
For i = 0 to 1000
If CheckBox1.Checked = True then (ここに中止した場合の処理 Exit Forなど)End IF
Data=wc.Download.data(a)
Status=False
Next
End Sub

Sub Button1_Click
t.Start()
Do Until Status = False
Application.DoEvents()

・その他の判断、処理CheckBox1のStatusで中止指示するなどTrue=中止)

Loop
End Sub

[ツリー表示へ]
タイトルRe^6: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5852
投稿日: 2007/07/17(Tue) 18:18
投稿者魔界の仮面弁士
> ・その他の判断、処理CheckBox1のStatusで中止指示するなどTrue=中止)
監視方向を逆にした方が良いと思いますよ。

メインスレッドがワーカスレッドの状態を逐次監視していたのでは、
いくらスレッドを分けたとしても、処理が十分に分散化されないでしょうし。


たとえば、
  『CheckBox1.Checked の値 True/False に応じて、
   Label1.BackColor を 赤/青 に切り替える』
という処理を実装することになったら、以下のどちらの方法で実装しますか?


 (案1) [フォームが CheckBox1 の状態を監視する手法]

  ループ中で DoEvents しながら CheckBox1.Checked の値を監視して、
  それに応じて、Label1.BackColor の色を切り替える。


 (案2) [CheckBox1 が、状態変化をフォーム側に通知する手法]

  CheckBox1 の CheckedChanged イベントのたびに CheckBox1.Checked の値を見て、
  それに応じて、Label1.BackColor の色を切り替える。


……通常は 案2 の方だと思いますが、それと同じことです。


非同期処理を中断させたいなら、たとえばデリゲートを使って、
メインがワーカに「中止依頼」を投げる形にするとか、あるいは
ワーカが定期的に「続行/中止を確認するイベント」を発行し、
メインがそれに答えるなどの仕様にした方が良いかと思います。

[ツリー表示へ]
タイトルRe^7: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5854
投稿日: 2007/07/17(Tue) 23:53
投稿者ポン太
なるほど!!
確かにその方が分かりやすいし簡単です。
共有の変数を互いに参照して、お互いが会話するようにやっていましたが、
相手がしゃべってる時に自分が勝手に動いてしまわないように
少しだけSleepを入れたりして非効率なことをしていたのですが、
凄くすっきりしそうです。
ありがとうございます。

[ツリー表示へ]
タイトルRe^5: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5849
投稿日: 2007/07/17(Tue) 16:55
投稿者魔界の仮面弁士
念のため確認。たとえば、ある変数に対して
 totalValue += 1
のように、単純に Integer 値を加算するだけの処理であっても、
これを複数のスレッドから同時に処理した場合、不整合を
起こす可能性がある……という事は認識されていますか?


> ↑の部分はApplication.DoEvents()を挟んで
> UL、DLスレッドとの同期の為にPulic変数(Status)で判断しています。

その変数は、メインスレッドの変数ですか? ワーカースレッドの変数ですか?
両スレッド間で変数を共有しようとしているのであれば、基本的に NG です。

もし、どうしても複数のスレッドからのアクセスが必要なのであれば、
その変数を読み書きするたびに、何らかの同期化を利用して、その共有データに対して
一度に 1 つのスレッドだけからアクセスされることを保証せねばなりません。

[ツリー表示へ]
タイトルRe^6: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5855
投稿日: 2007/07/18(Wed) 00:03
投稿者ポン太
確認のための変数はダウンロードスレッドの変数です。
別スレッドで処理をして良い状態になったら
それを通知するためのものです。
これは両方から内容を変更するようにはなっていません。
(ダウンロードスレッドがメインスレッドに動いていいよを通知する為のものです。)

でもApplication.DoEvents()を入れてループをする中に
System.Threading.Thread.Sleep(100)
とかを入れないとならないので、この0.1秒の間に
通知の変数が「動いて良いよ」になって、
すぐに次のダウンロードを始めて「動いたらダメ」になってしまう可能性もあるので、
こちらにもSleepを入れたりしないとならず、とてもややこしくなっておりました。
たった1:1の通信をするだけでもなかなか大変なものですね。

[ツリー表示へ]
タイトルRe^3: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5843
投稿日: 2007/07/17(Tue) 10:50
投稿者魔界の仮面弁士
2005 なら、WebClient の Async 系メソッドや、BackgroundWorker の利用がおすすめです。

> ご回答頂いたようにするとフォームがロックしてしまうため、
> やはりスレッドを分けたいです。
だったら、ループ等で「待機」してはまずいと思いますよ。

> 私の出来る方法だとApplication.Doevents()を入れる隙間がありません。
DoEvents の使用はできるだけ避けましょう。特にマルチスレッド時には。

> 実行したいことがあるので、やはりスレッドを再度実行したいです。
処理を一時中断して、そこから再開するのでしょうか?
そうではなく単に最初からやり直すのであれば、Thread を再生成するだけで済むと思いますよ。

[ツリー表示へ]
タイトルRe^4: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5845
投稿日: 2007/07/17(Tue) 13:47
投稿者ポン太
こんにちは。お返事ありがとうございます。

Frameworkは1.1なので、2.0にならないか色々試したのですが、
VB.NETでは2.0にはならないようで、
教えて頂いた便利な機能が全て使えず、諦めてWebClientを使用しております。

>DoEvents の使用はできるだけ避けましょう。特にマルチスレッド時には。
今後の為にも教えて頂けると助かるのですが、これはどのような理由からでしょうか?

メインスレッドで待機してもApplication.Doevents()を入れて
フォームを変更できるようになりますし、特に問題は無いように思うのですが・・・

処理を中断して再開することは、スレッド自体が再開できれば対応できるので
(For i=o to 1000のiの値を覚えていて再実行すれば良いので)
Threadを再生成する方法を調べてみたいと思います。
ありがとうございました。

[ツリー表示へ]
タイトルRe^5: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5847
投稿日: 2007/07/17(Tue) 15:44
投稿者魔界の仮面弁士
> VB.NETでは2.0にはならないようで、
.NET 2.0 対応のバージョンは、Visual Basic 2005 (VB8) です。
1.1 なら、2003 (VB7.1) ですね。

>> DoEvents の使用はできるだけ避けましょう。特にマルチスレッド時には。
> 今後の為にも教えて頂けると助かるのですが、これはどのような理由からでしょうか?
メソッド処理中に別のメソッドが処理される機会を与えることになるため、処理が
複雑になってしまう可能性があるからです。理解した上で使う分には問題ありませんけど。

また、そもそもマルチスレッド対応のアプリを書くというのであれば、
メインスレッドをループ待機させるような処理は、その分、処理速度を
遅くしてしまいますので、あまり効果的な使い方ではないでしょう。

> Threadを再生成する方法を調べてみたいと思います。
開始直前に「t = New 〜(AddressOf 〜)」するだけですよ。

[ツリー表示へ]
タイトルRe^6: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5856
投稿日: 2007/07/18(Wed) 00:09
投稿者ポン太
VBのバージョンは2003でした。

確かに複雑なのはよくないですよね。
それも今回のようにもっと良い方法があるならなおさらでした。

t = New 〜(AddressOf 〜)の方法も教えて頂いてありがとうございました。
とても便利そうで今後多用できそうです。

[ツリー表示へ]
タイトルRe^6: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5857
投稿日: 2007/07/18(Wed) 03:58
投稿者ポン太
たびたび申し訳ございません。

また一つ分からなくなってしまいました。お助け頂けないでしょうか。
WebClientのDownloadFileを実行中にプログレスバーで転送した量を
0%−100%で表示したいのですが、(ダウンロードの場合)
最初HttpWebRequestとHttpWebResponseでファイルのサイズを取得して、
Sub Downloading()というものがあり、その中で
DownloadFileを実行して出来たローカルファイルのファイルサイズを
Do Loopで1秒おきくらいで確認してプログレスバーを進めようと思っているのですが、
Downloading()をメインスレッドで実行することは出来ないでしょうか。

主な部分だけですが具体的には下記のようになっています。

Private Sub Button1_Click ・・・
t.Start()
End Sub

Sub Download()
Label1.Text="ダウンロード中"
Downloading()
FileNameの空のファイルを作成
Wc.DownloadFile(URL,FileName)
Label1.Text="ダウンロード完了"
End Sub


Sub Downloading()
Do Until Label1.Text = "ダウンロード完了"
ローカルのファイルのサイズを確認
プログレスバーを進める
Application.DoEvents()
System.Threading.Thread.Sleep(1000)
Loop
End Sub

このままですとDownload()内のDownloading()を呼び出したところで
ずっと停止してしまいます。
Downloading()をメインスレッドで実行できればと思うのですが、
もう一つスレッドを用意しないとならないでしょうか?

またはWc.DownloadFileメソッドでファイルを転送する際に
転送サイズをプログレスバーに反映できる良い方法がありましたら
アドバイスを頂けると幸いです。

[ツリー表示へ]
タイトルRe^7: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5864
投稿日: 2007/07/18(Wed) 18:40
投稿者魔界の仮面弁士
今回の件で使えるかどうかは未検証ですが、非同期ダウンロードに関して、下記も参考に。
http://dobon.net/vb/dotnet/internet/webrequest.html

> Do Loopで1秒おきくらいで確認してプログレスバーを進めようと思っているのですが、
その、ループ監視を用いた開発スタイルを見直しましょう。(^^;

秒間隔の監視なら、Timer コンポーネントを使った方が良いですよ。

[ツリー表示へ]
タイトルRe^8: マルチスレッドでスレッドを何度も実行する方法を教えてください
記事No5865
投稿日: 2007/07/19(Thu) 00:24
投稿者ポン太
Timer コンポーネント試しました。
すごく便利ですね。
これを使うことにします。
何度もありがとうございました。

[ツリー表示へ]