C#, C♯, C#相談室 Part73

このエントリーをはてなブックマークに追加
952 ◆BvcplLXSGo :2012/07/12(木) 22:22:24.94
てす
953デフォルトの名無しさん:2012/07/12(木) 22:23:46.78
>Invokeを使ってコントロールを操作しようとしている為
Task.Factory.Start(() => worker(i));
ThreadPool.QueueUserWorkItem(_ => worker(i));
何の問題もないがお前はいったい何を言ってるんだ
954デフォルトの名無しさん:2012/07/12(木) 22:31:56.61
>>953
サンキュー

Task.Factory.StartNew(() => worker(i));
ThreadPool.QueueUserWorkItem(_ => worker(i));

でなんとか出来そうです。
Taskってやつ便利ですねぇ。
FW4からなのか。XPで動くかちと心配。

Invokeでメインスレッドより生成されたコントロール操作の検証をしてみます。
955デフォルトの名無しさん:2012/07/12(木) 22:34:55.03
ピンボケなのかボケなのか解らないがinvokeが理解できない
956デフォルトの名無しさん:2012/07/12(木) 22:39:15.10
957デフォルトの名無しさん:2012/07/13(金) 00:20:44.55
Invokeを使ってコントロールを操作しようとしている為
Taskは今回は使えそうにないです。

キリッ!
958953:2012/07/13(金) 00:28:14.22
今気付いたけど>>954のコードはiのスコープの関係で間違ってるわ
for (int i = 0; i < dgv.Rows.Count; i++)
{
 int temp = i;
 Task.Factory.StartNew(() => worker(temp)); // もちろんThreadPoolでもいい
}
こうしないとworkerが同じ引数で呼び出される可能性がある
959デフォルトの名無しさん:2012/07/13(金) 00:31:09.22
>>958
ありがとうございます。
ブレークポイントを配置しデバッグで
おっかけていたら、 なぜか同じ i = 0 や i= 1 が2回も来ており
悩んでいました。
960デフォルトの名無しさん:2012/07/13(金) 00:31:58.05
酷いコードを張るお兄さんやでぇ
961デフォルトの名無しさん:2012/07/13(金) 05:58:20.38
>>958
for (int i = 0; i < dgv.Rows.Count; i++)
{
 Task.Factory.StartNew(() => worker(i));
}

だとなんで駄目なん?メカニズムを知りたい
962デフォルトの名無しさん:2012/07/13(金) 09:21:05.66
>>961
C系言語のforではループ変数のiのスコープはこうなる
{ int i; for (i = 0; 略) { 略 } }
ラムダ式の中でiが使用されているので、ブロックを抜けた後もiが使用される必要があるから、
{ Scope_i _i = new Scope_i(); for (_i.i = 0; _i.i < count; _i.i++) { StartNew(() => worker(_i.i)) } }
変数iはこんな感じでスタックじゃなくてヒープに確保される。
すべてのラムダ式が共通の変数を参照してるから、タイミングによってはworkerが同じ引数で呼び出されることになる。
>>958のようにループ内で変数を宣言しなおせば
for (int i = 0; i < count; i++) { Scope_temp _temp = new Scope_temp(); _temp.temp = i; StartNew(() => worker(_temp.temp)) }
となって、変数tempのインスタンスがループ毎に新しく作られる。
963デフォルトの名無しさん:2012/07/13(金) 09:23:13.47
>>962
Excellent!!
964デフォルトの名無しさん:2012/07/13(金) 18:12:26.24
C#でiPhoneアプリ作れますか?
965デフォルトの名無しさん:2012/07/13(金) 18:26:16.99
ますん
966デフォルトの名無しさん:2012/07/13(金) 18:37:16.69
>>964
ggrks
967デフォルトの名無しさん:2012/07/13(金) 19:42:21.91
>>996
you should speak japanese correctly. hahha-www
968デフォルトの名無しさん:2012/07/13(金) 20:01:02.49
空気脳がアンカー間違えてやんのw
969デフォルトの名無しさん:2012/07/13(金) 21:36:09.26
this isn't a mistake rather my message for future
970デフォルトの名無しさん:2012/07/13(金) 22:17:13.61
private void btn_publish_Click(object sender, EventArgs e)
{
  for (int i = 0; i < 3; i++)
  {
    int temp = i;
    //Task.Factory.StartNew(() => worker(temp)); // もちろんThreadPoolでもいい
    ThreadPool.QueueUserWorkItem(_ => worker(temp)); // もちろんThreadPoolでもいい
  }
}

void worker(int i)
{
  Invoke(new DelegatePublishQuery(PublishQuery),i);
}

private void PublishQuery(int i)
{
  while(true)
  {
    lbl_status.Text = " i = [" + i.ToString() + "]";
    Thread.Sleep(10000); //10秒待機
  }
}

スレッドでループをかけているにも関わらず、次のスレッドのみ生きている様です。
i = 0 や i = 1 のスレッドは死んだのでしょうか?
i = [2]
971デフォルトの名無しさん:2012/07/13(金) 22:19:35.52
全くスレッドの意味ないだろそれ
重い処理はInvokeじゃなくてworkerの中でやらないと
972デフォルトの名無しさん:2012/07/13(金) 22:20:29.78
Invokeって多分Control.Invokeだと思うけど、
それって「メインスレッドでこの処理やってね」って意味だぜ
973デフォルトの名無しさん:2012/07/13(金) 22:21:20.97
Invokeのおかげで全部GUIスレッドで実行されとる
974デフォルトの名無しさん:2012/07/13(金) 22:22:05.39
日本語でおk。

質問の意味わからなさすぎて望む答えになってるかどうかわからないけど、
Control.Invoke した時点でUIスレッドに処理戻るから、
そのコード実行したらUIがフリーズするだけ。
975デフォルトの名無しさん:2012/07/13(金) 22:22:19.59
>>971
複数スレッドを作成してWindowsForm上の項目(ここだと labelになります。)を
更新する為に Invokeでメソッドを指定しています。

>>970
でいうところの一番最後のループ(スレッド)のみ繰り返されているんですよねぇ。
976デフォルトの名無しさん:2012/07/13(金) 22:26:36.20
>>971 >>972 >>973 >>974
要するにやりたい事というのは、

スレッドを連続で作成し、それぞれスレッド毎に待機時間がばらばらの状態で、
スレッドがスリープに入る直前で共通のコントロール(ラベル)の値を書き換えたいのです。

しかし、Invokeを使わないとマルチスレッドプログラミングでは
コントロールをスレッドから操作する事が出来ないとの事なので
Invokeを使っています。

うーん、誰か私がやりたい事を実現出来るコードを教えて下さい。


977デフォルトの名無しさん:2012/07/13(金) 22:27:10.12
>lbl_status.Text = " i = [" + i.ToString() + "]";

ここだけInvokeすれば
978970:2012/07/13(金) 22:30:07.97
コードを次の様に変えてみましたところ、やはりマルチスレッドプログラミングの為、エラーが発生しました。
重たい処理というよりスレッドを連続で走らせ、スレッド毎に設定された時間待機させたいです。

Aスレッドが待機に入ったとしてもBスレッドは実行してコントロールの値を書き換える、といったイメージです。

void worker(int i)
{
  // Invoke(new DelegatePublishQuery(PublishQuery),i);
  // ↓
  PublishQuery(i);
}
979デフォルトの名無しさん:2012/07/13(金) 22:30:10.34
突っ込みどころ多すぎる。

UI書き換えるところだけInvokeで覆う
Thread.Sleepで待機なんてパフォーマンス落とすだけだからTimer使え
980デフォルトの名無しさん:2012/07/13(金) 22:33:28.79
>>979
そこは「仮想重い処理」だから実装するときは別でしょ
981デフォルトの名無しさん:2012/07/13(金) 22:35:51.57
意図通りに動いたとしても、[0]や[1]が表示されてる時間が短すぎる可能性があるよね
982デフォルトの名無しさん:2012/07/13(金) 22:36:08.35
いかん、マルチスレッド難しい。。。

this.Refresh(); 

やったら怒られるし。
983デフォルトの名無しさん:2012/07/13(金) 22:37:05.99
>>981
表示時間は短くても良いのです。
ファイルに出力する等して、ちゃんと [0][1][0]・・・という風にマルチスレッドで
動いている事の確認がしたいのです。
984デフォルトの名無しさん:2012/07/13(金) 22:39:00.26
private void PublishQuery(int i)
{
  while(true)
  {
   //↓このあたりにブレークポイントを張って、 i の値を監視してますが常に 2 だけなんです。なんで 1 や 2 がこない?
    lbl_status.Text = " i = [" + i.ToString() + "]";
    Thread.Sleep(10000); //10秒待機
  }
}
985デフォルトの名無しさん:2012/07/13(金) 22:42:41.12
こうするんだよ
void worker(int i)
{
 while (true)
 {
  Thread.Sleep(10000); //10秒待機
  Invoke(_ => { lbl_status.Text = " i = [" + i.ToString() + "]"; });
 }
}
986デフォルトの名無しさん:2012/07/13(金) 22:47:14.74
>>985
試してみましたが

Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
デリゲートタイプでは無い為に、ラムダ表現をデリゲートに変更出来ません。

こんなエラーが出ちゃいます。
???意味わからん。
987デフォルトの名無しさん:2012/07/13(金) 22:50:40.45
WinFormsのInvokeがレガシーすぎる…
ActionとかFuncでなく、Delegate受け取るメソッドとか絶滅すればいいのに。
988デフォルトの名無しさん:2012/07/13(金) 22:51:28.25
ラムダ式は直接Delegate型に変換できんので(Action)(()=>{})と書けってこと
989デフォルトの名無しさん:2012/07/13(金) 22:52:47.63
>>987
拡張メソッド作ってごまかす、だねえ。
990デフォルトの名無しさん:2012/07/13(金) 22:55:26.59
WPFにはDispatcher.InvokeAsyncが追加されたというのに
991デフォルトの名無しさん:2012/07/13(金) 22:56:47.47
>>988
ありがとうございます!!
やりたい事が出来そうです!! 感謝!!

あと、↓も参考になりました!!
http://bartwullems.blogspot.jp/2011/01/cannot-convert-lambda-expression-to.html
992デフォルトの名無しさん:2012/07/13(金) 22:57:26.98
つうかテストするならConsole.Write使って標準出力に出せばいいのに
993デフォルトの名無しさん:2012/07/14(土) 12:15:43.39
MS厨の巣
994デフォルトの名無しさん:2012/07/14(土) 12:42:17.03
うぜえMS厨
995デフォルトの名無しさん:2012/07/14(土) 12:44:19.44
MVP=MS厨
996デフォルトの名無しさん:2012/07/14(土) 13:43:16.33
MSDNていくら?
997デフォルトの名無しさん:2012/07/14(土) 13:44:45.55
$1,199.00
998デフォルトの名無しさん:2012/07/14(土) 13:46:24.62
\94960.8(税別)
999デフォルトの名無しさん:2012/07/14(土) 13:46:56.60
ume
1000デフォルトの名無しさん:2012/07/14(土) 13:47:26.91
ume
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。