C#のスレッドに上位から値を渡す方法

このQ&Aのポイント
  • C#でスレッドに上位から値を渡す方法について知りたい。
  • 装置の制御に使われるスレッドに、上位から値を渡す方法について教えてください。
  • C#のスレッドに上位から値を渡す方法について教えてください。
回答を見る
  • ベストアンサー

C# のスレッドに、上位から値を渡すには?

いつもいつもお世話になっています。 ある装置を制御するためのプログラムをC#で作っています。 装置の状態を保持したり制御するために、下のようなクラスを作りました。 制御のためのコマンドの送受信はUDPを利用して、 その部分をスレッドにしてみました。 上位からコマンドをスレッドに渡せば制御できるかな、と思ったのですが、 スレッドにコマンドを渡す方法が分かりません。  Device dev = new Device;  dev.Start(); // スレッドが起動    :  dev.Control(1); // コマンドとして 1 を与える これで、1をスレッドに渡すには、どのようにすればいいのでしょうか? むかし、MFC C++ を少しかじったことがあるのですが、 そのときは、コマンド領域のポインタをスレッドに渡し、 スレッドの中からその領域を参照していました。 C#ではどのようにするのが普通でしょうか? よろしくお願いします。 (抜粋)  class Device  {    // 装置運転開始    public void Start() {      ComThread comThread = new ComThread();      comThread.Start();    }    class ComThread    {      public void Start()        var udpThread = Task.Factory.StartNew(()=>UDPThread());      }      public void Stop()        // スレッド停止処理      }      public void Control(int cmd)        // スレッドにコマンドを通知        cmd に入っている値をスレッドに渡したい      }      static void UDPThread()      {        for (;;) {          if (...) {  ← 上位から何らかの値を渡す必要            // コマンド送信            制御コマンド送信~レスポンス受信          }          Thread.Sleep(1000);        }      }    }  } 余談ですが、AJAXとか独立したカテゴリなのに、 C#はその他なんですね。(^ ^)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

>  static int ctrlCmd = 0; > でコマンド変数を定義し、 > スレッドからこの変数を参照しています。 > これは作法的に誤りではないでしょうか? この作りだと,ctrlCmdはDevice.ComThreadクラスの非staticなフィールドにすると思います。 Deviceのstaticであるということは,全Deviceインスタンス・全Device.ComThreadインスタンスに対して1つしか持てなくなりますが, クラスの構造は,Deviceは複数,さらに1つのDeviceに対してDevice.ComThreadが複数,という作りのように見えます。 この構造とctrlCmdの状況が合っていないので,コードを読んでいて不思議に感じます。

ogu-ne
質問者

お礼

この度はいろいろとありがとうございました。 なんとか次の段階に進むことができそうです。 スレッドひとつとっても、 いろいろな実現方法があるようで、 排他のことも考えないといけないし、 さらには、スレッド中から発行したイベントの中でボタンのEnabledを変更しようとすると例外が発生したりと、 まだまだ知らないといけない事柄がありますが、 なんとかやっていきたいと思います。 どうもありがとうございました。

ogu-ne
質問者

補足

度々本当にありがとうございます。 確かにご指摘のとおりです。 static の意味の理解がよくできていませんでした。 Device クラスは複数存在し、 その中にひとつの UDPThread スレッドがあるようにしたかったのです。 UDPThread を static にしているとctrlCmd にアクセスできないので、 UDPThread の static も外しました。 動作しているようですが、行儀のよいコーディングかどうか分かりません。

その他の回答 (1)

回答No.1

まず,スレッドはメモリ空間が分離していないですから,同期や排他の問題はともかく,フィールドに書き込めば他のスレッドから参照可能です。 使い方によっては,BlockingCollection http://msdn.microsoft.com/ja-jp/library/dd267312.aspx やConcurrentQueue http://msdn.microsoft.com/ja-jp/library/dd267265.aspx など,System.Collections.Concurrentのコレクションが役立つかと思います。 APIに似た方式では,System.ThreadingにAutoResetEventやManualResetEventといった同期用のクラス, http://msdn.microsoft.com/ja-jp/library/system.threading.autoresetevent.aspx http://msdn.microsoft.com/ja-jp/library/system.threading.manualresetevent.aspx MonitorやSemaphoreといった排他用のクラス http://msdn.microsoft.com/ja-jp/library/system.threading.monitor.aspx http://msdn.microsoft.com/ja-jp/library/system.threading.semaphore.aspx が存在しますし,Interlockedクラスとintフィールドによる同期/排他も可能です。 http://msdn.microsoft.com/ja-jp/library/system.threading.interlocked.aspx

ogu-ne
質問者

お礼

回答をありがとうございます。 すこし光が見えてきました。 > スレッドはメモリ空間が分離していないですから,同期や排他の問題はともかく,フィールドに書き込めば他のスレッドから参照可能です ということから、以下のように修正してみました。  static int ctrlCmd = 0; でコマンド変数を定義し、 スレッドからこの変数を参照しています。 これは作法的に誤りではないでしょうか? (排他に関しては無視しています。) (抜粋) class Device  {    static int ctrlCmd = 0; ← ★★★ 追加 ★★★    // 装置運転開始    public void Start() {      ComThread comThread = new ComThread();      comThread.Start();    }    class ComThread    {      public void Start()        var udpThread = Task.Factory.StartNew(()=>UDPThread());      }      public void Stop()        // スレッド停止処理      }      public void Control(int cmd)        ctrlCmd = cmd; ← ★★★ 追加 ★★★      }      static void UDPThread()      {        for (;;) {          if (ctrlCmd == 1) { ← ★★★ 追加 ★★★            // コマンド送信            制御コマンド送信~レスポンス受信          }          Thread.Sleep(1000);        }      }    }  } 教えてくださったリンク、大変参考になります。 排他やキューなど、これからまだまだ覚えないといけないことがあるようです。 プログラミングに興味があり、これからも勉強していきたいと思います。

関連するQ&A

  • C# スレッド終了の監視について

    お世話になります。 C#2005でプログラムを作成しております。 マルチスレッドでの、スレッドの終了の監視のことでご質問させていただきます。 下記のコードを実行すると、問題なく実行されます。 ------------------------------------------------------------------------------------ private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入 */ } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ このスレッドの終了を監視したく、下記のコードを追加してデバッグしてみましたが、 スレッドが実行されませんでした。 ------------------------------------------------------------------------------------ int isRcvSearchFlg = 0; private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); // スレッドが終了するまで待機する for (; ; ) { if (isRcvSearchFlg == 1) { break; } } } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入 */ isRcvSearchFlg = 1; } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ また、以下も試してみましたが、結果は同じでした。 ------------------------------------------------------------------------------------ private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); // スレッドが終了するまで待機する RcvSetThread.Join(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入処理 */ } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ スレッドの終了を監視する方法がわからず困っております。 お手数ですが、ご教授いただきたくよろしくお願い申し上げます。

  • c# スレッド間でのデータの共有

    C#でメインプロセスと生成されたスレッド間でデータの共有をさせたいのですがどのようにすればいいのでしょうか。ご教授お願い致します。 ・メインプロセス(A) ・Aから生成されたスレッド(B) 例えば、AとBで変数の値をそれぞれ読み書きさせたい場合 どのようにすればよいのでしょうか。 class TEST { public int flag; // メインプロセス(A) public static void Main() { Thread t = new Thread(new ThreadStart(abc)); t.IsBackground = true; t.Start(); while(ture) { Thread.Sleep(10); Console.WriteLine("A:{0}",flag); } } // Aから生成されたスレッド(B) public void abc() { Console.WriteLine("B:{0}",flag); flag++; } }

  • C#で引数を渡して、スレッド用の関数をよびだすには?

    C#でスレッドを使う場合、引数が渡せません。 具体的には、 Thread temp=new Thread(new ThreadStart(message)); temp.Start(); private void message(){ ~} と、なり、ThreadStart(message)の部分で、 ThreadStart(message(mystr))とし、 private void message(string s){} 書くことができないのです。 しかし、関数に、引数を渡せないのは、不便です。 何か、方法は、ないでしょうか。

  • スレッド動かず

    本の真似をして、スレッドを書いてみたんですがに何も起こりませんでした。全く分かりません。どうすれば良いでしょうか? public class Frame1 extends Frame implements Runable{ ................. ................. Thread kick = new Thread(this); int time; public void start() { if (kick ==null) kick.start(); } public void run() { while (kick == Thread.currentThread()) { time++; String s = Integer.toString(time); textArea1.append( s + "\r\n"); try{ Thread.sleep(1000); }catch(InterruptedException e){} } }

    • ベストアンサー
    • Java
  • スレッド1とスレッド2を交互に実行するには?

    スレッド1→スレッド2→スレッド1・・・と同期を取り合いながら交互にスレッドを動かしたいのですが、Thread.getState()を用いないで実現するよい方法はないでしょうか? どうしてもデッドロックが発生しうる方法しか思いつかず困っています。 例えば以下のプログラムで1212と交互に表示させたい場合です。 以下のプログラムは当然デッドロックになりますが、やりたいことを伝えるために載せておきます。 Object obj; //スレッド間通信用のobject class Test1 extends Thread {  public void run() {   while(true) {    System.out.print("1");    synchronized (obj) {     obj.notify();//相手をnotifyして     obj.wait();//自分はwait    }   }  } } class Test2 extends Thread {  public void run() {   while(true) {    System.out.print("2");    synchronized (obj) {     obj.notify();     obj.wait();    }   }  } } new Test1().start(); new Test2().start();

    • ベストアンサー
    • Java
  • Threadの終了

    http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/index.html を見ると,スレッドの止め方が書いてありますが, これは,スレッドblinker内でループが回っていて初めてうまく行く, と(間違ってるかもしれませんが)理解しています. では下記のように,Thread2でループが回っていない場合は (*)の位置でThread2を止めるにはどうすればいいのか, 教えてくださる方はいらっしゃいませんでしょうか. (**)のClassAではSWTでGUIを表示させていて, それをThread1から閉じるというのが目的です. GUIを閉じない限りその先には進まないので, ループを回しThread2のrun()内で待機させることが出来なくて. public class Thread1 { Thread1(){ Thread2 t2 = new Thread2(); t2.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { } (*)ここでThread2を終了させたい. } public static void main(String args[]){ new Thread1(); } class Thread2 extends Thread { public void run() { new ClassA(); ・・・(**) } } }

    • ベストアンサー
    • Java
  • スレッドが実行中かどうかの確認

    画面の中にボタンを作成し、そのボタンを押すとスレッドが実行される機能を作成しました。 「一度ボタンを押してスレッドが実行中の場合は処理を実行しない」 という処理を実装したいです。 上記の処理を以下のソースで考えていますが(1)の部分がわかりません。 そもそも(1)のようなことが可能かもわかっていない状況です。 (1)のようなことは可能なのでしょうか? どなたか、知恵を貸していただければと思います。 よろしくお願い致します。 /* ソース */ public class ExThread1 extends Thread{  public void run() {   // 処理  } } public class TEST {  public static void main(String[] args){   ExThread1 thread1 = new ExThread1();   // (1)スレッドが実行中ならstartしない   if(スレッドが実行中ではない){    thread1.start();   }  } }

    • ベストアンサー
    • Java
  • 2つのスレッドの実行について

    お世話になります。 VS2005C#で作成しております。 以下のコードにてスレッドを2つ実行させ、終了を監視する処理を記述しました。 ----------------------------------------------------------------------------------------------------------- isRcvSearchFlg = 0; isFwdSearchFlg = 0; private int SetDataTreeView() { // それぞれのデータ格納処理をスレッドで処理する Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); Thread FwdSetThread = new Thread(new ThreadStart(this.FwdDataSet));   RcvSetThread.Start(); FwdSetThread.Start(); // 両方のスレッドが終了するまで待機する while (isRcvSearchFlg != 1 && isFwdSearchFlg != 1) Application.DoEvents(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* メインフォーム内のDatagidview(1)への値の代入 */ isRcvSearchFlg = 1; } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } delegate void FwdDataSetDelegate(); private void FwdDataGridSet() { /* メインフォーム内のDatagidview(2)への値の代入 */ isRcvSearchFlg = 1; } void FwdDataSet() { Invoke(new FwdDataSetDelegate(FwdDataGridSet)); } ----------------------------------------------------------------------------------------------------------- RcvDataGridSet、FwdDataGridSetでログを出力して、進行状況を監視しておりますが、どうも2つのスレッドが同時に走っていないようなのです。 原因として考えられることはございますでしょうか。 また、同時に走らせるコードはありますでしょうか。 お手数ですが、ご教授いただきたく宜しくお願い申し上げます。

  • ThreadとRunnableのlogへの表示差異

    マルチスレッドでsleep()の時間を指定して動かすのを前提で、 Threadを継承した時は、時間通りに(リアルタイムで) eclipseのコンソールへ表示されるのですが、 Runnableをインプリメントしての動作では、 eclipseのコンソールに一瞬で表示されるのは何故でしょうか? public class MultiThread3 implements Runnable{ int time; MultiThread3(int time) { this.time = time; } public void run() { for(int i=0; i<5; i++) System.out.println("No."+i+":"+Thread.currentThread().getName()); try{ Thread.sleep(time); }catch (InterruptedException e) {} } } class MultiThreadTest3{ public static void main(String[] args) { MultiThread3 a = new MultiThread3(500); MultiThread3 b = new MultiThread3(700); MultiThread3 c = new MultiThread3(1100); Thread ta = new Thread(a); Thread tb = new Thread(b); Thread tc = new Thread(c); ta.setName("A"); tb.setName("\tB"); tc.setName("\t\tC"); ta.start(); tb.start(); tc.start(); } }

    • ベストアンサー
    • Java
  • Visual c# スレッド

    プログラム初心者です。 Visual c#にてスレッド関数を使ったプログラムを見よう見まねで 作りました。 スタートボタンを押すとピクチャーボックスの位置が 左から右へ移動し、ストップボタンを押すと止まる。 ピクチャーボックスの位置をテキストボックスに表示する。 というプログラムのつもりです。 デバックの状態でスタートボタンを押すとエラーメッセージが出て テキストボックスに位置を書き込むの関数のところが緑色にハイライトされます。エラーの内容は「有効でないスレッド間の操作」とありますが、どうしたら良いのか分かりません。 エラーの直し方を教えてください。 プログラムコードは以下です。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace bit_map_08._1._ { public partial class Form1 : Form { private Thread thread; static private int Position = 0; static private int i; static bool BtnOnFig; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { thread = new System.Threading.Thread(newSystem.Threading.ThreadStart(MainThread)); thread.Start(); } private void PointMove() { if (i < 300) { i = i + 1; Position = Position + i; textBox1.Text = Convert.ToString(Position); pictureBox1.Left = (Position); } if (i == 300) { i = 0; } } private void MainThread() { while( true ) { Thread.Sleep(100); if (BtnOnFig == true) { PointMove(); } } } private void button1_Click(object sender, EventArgs e) { BtnOnFig = true; } private void button2_Click(object sender, EventArgs e) { BtnOnFig = false; } } }

専門家に質問してみよう