- PR -

【VC#2005】PostThreadMessageを使う方法

1
投稿者投稿内容
Makoto
大ベテラン
会議室デビュー日: 2004/03/31
投稿数: 133
投稿日時: 2007-07-10 17:43
いつもお世話になっております。

久しぶりにプログラムしていて思ったのですが、
下記ってどうなっているんでしょうか?
ご存知の方いらっしゃいましたら教えて下さい。

『VC++のSendMessage』は、『C#のControl.Invoke』に対応し、
『VC++のPostMessage』は、『C#のControl.BeginInvoke』に対応しています。

では『VC++のPostThreadMessage』は、
C#ではどうやって実装したらよいのでしょうか?

メッセージループをしていて随時メッセージを受信できるスレッド
(=ワーカースレッドではない)を利用してプログラムしたいのですが、
C#ではどのように実装してやればよいのでしょうか?

@スレッドからの画面Formへのアクセスは、Control.BeginInvokeを利用

 Form←Thread

Aフォームから既存のスレッドへメッセージングする方法は???
 (どう実装するのでしょうか?) 

 Form→Thread

以上、お忙しいとは思いますが、よろしくお願いいたします。
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2007-07-11 00:46
こんばんは。

引用:

Makotoさんの書き込み (2007-07-10 17:43) より:
『VC++のSendMessage』は、『C#のControl.Invoke』に対応し、
『VC++のPostMessage』は、『C#のControl.BeginInvoke』に対応しています。



どうでも良いことですが・・・
同期・非同期(受信側/呼び出し側スレッドがブロックされるかどうか)という意味では正しいと思いますが、
実装上はControl.InvokeもControl.BeginInvokeも、どちらもPostMessageが使われていますね。

引用:

では『VC++のPostThreadMessage』は、
C#ではどうやって実装したらよいのでしょうか?

メッセージループをしていて随時メッセージを受信できるスレッド
(=ワーカースレッドではない)を利用してプログラムしたいのですが、
C#ではどのように実装してやればよいのでしょうか?

Aフォームから既存のスレッドへメッセージングする方法は???
 (どう実装するのでしょうか?) 

 Form→Thread



少し順序立てて考えてみたいと思います。

まず、メッセージループを持つスレッドを作成するには
そのスレッドでApplication.Runメソッドを呼び出す必要があると思います。

つぎに、FormやControlをもたないようなスレッドに処理させたい場合、
Application.AddMessageFilterメソッドで、直にウィンドウメッセージを処理するしかなさそうです。

と考えると、P/Invokeで直にWindows APIのPostThreadMessageを呼び出さないといけないのではないかと思います。


というわけでコードを書いてみました。
#つたないコードでスイマセン。.NET/C#のコードをほとんど書いたことないので。

Program.cs
コード:
static class Program
{
	// サブスレッドID
	public static uint idSubThread = 0;
	// PostThreadMessage用メッセージ
	public static uint MyMsg = Win32.NativeMethods.RegisterWindowMessage("MyMsg");

	// サブスレッドメッセージ処理
	class SubThreadProc : IMessageFilter 
	{
	    public bool PreFilterMessage(ref Message m)
	    {
	        if (m.Msg == MyMsg)
	        {
	            MessageBox.Show("サブスレッド処理");
	        }
	        return true;
	    }
	}

	[STAThread]
	static void Main()
	{
	    // サブスレッドの起動
	    new Thread(delegate()
	    {
	        // idSubThread = Thread.CurrentThread.ManagedThreadId;  // ×
	        // idSubThread = System.AppDomain.GetCurrentThreadId(); // deprecated 
	        idSubThread = Win32.NativeMethods.GetCurrentThreadId();

	        // メッセージフィルタの設定
	        Application.AddMessageFilter(new SubThreadProc());

	        // サブスレッドのメッセージループ処理
	        Application.Run();

	        MessageBox.Show("サブスレッド終了");

	    }).Start();


	    // メインスレッドのフォームを表示
	    Application.EnableVisualStyles();
	    Application.SetCompatibleTextRenderingDefault(false);
	    Application.Run(new Form1());
	}
}



Form1.cs
コード:
public partial class Form1 : Form
{
	public Form1()
	{
	    InitializeComponent();
	}

	// ボタンクリック時
	private void button1_Click(object sender, EventArgs e)
	{
	    // サブスレッドへメッセージ送信
	    Win32.NativeMethods.PostThreadMessage(Program.idSubThread, Program.MyMsg, 0, 0);
	}

	// フォームクローズ時
	private void Form1_FormClosed(object sender, FormClosedEventArgs e)
	{
	    // サブスレッドを終了させる
	    Win32.NativeMethods.PostThreadMessage(Program.idSubThread, (uint)Win32.WindowMessages.WM_QUIT, 0, 0);
	}
}


Makoto
大ベテラン
会議室デビュー日: 2004/03/31
投稿数: 133
投稿日時: 2007-07-11 16:19
早速の回答ありがとうございます。

非常に参考になりました。
(興味ですが、Control.Invokeの内部実装ってどうするとみれるんですか?)

ただ私の質問の仕方がまずかったようなので
再度質問させてください。

C++では(Dialog-Thread間は、)メッセージ通信で非同期処理を実装する
実装モデルを提供しています。

C#ではThread側にメッセージ用に使用する関数”Invoke”のようなものが
見当たりません。
(Form側には、Control.Invokeがあります。)
C#でForm−Thread間で非同期通信する際の実装モデルは
どのようなものなのでしょうか?

正直、C#のThreadを無限ループさせて、排他したキューを実装すれば
自前で実現できますが、
ライブラリで用意されているのならばそちらを使用したいのです。

が、今までそういったサンプルを見たことがありません。
(『ワーカスレッドの例』、『同期オブジェクトで呼出側がブロックしてしまう例』
ばかり目にします。)

で質問なのですが、

C#で上記のような実装をする場合のモデル(MSの提唱するデザインパターン)
のようなものはあるのでしょうか?

または、このようなケースでは皆さんはどのように実装されているのでしょうか?
教えて下さい。

以上、お忙しいとは思いますが、よろしくお願いいたします。
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2007-07-11 16:51
引用:

Makotoさんの書き込み (2007-07-11 16:19) より:
C++では(Dialog-Thread間は、)メッセージ通信で非同期処理を実装する
実装モデルを提供しています。



「C++」ではないです。
メッセージ通信を提供しているのはWindowsです。

引用:

C#ではThread側にメッセージ用に使用する関数”Invoke”のようなものが
見当たりません。
(Form側には、Control.Invokeがあります。)



で、Win32のWindowはシングルスレッド用に作られているので、
異なるスレッドで作成されたWindowオブジェクトを処理することができません。
マネージできれいに処理するためにInvokeがあるんです。
メッセージ用・スレッド間通信用にあるわけではありません。
もしスレッド間通信ようにあるのでしたら
Threadクラスにあるはずです。

引用:

C#で上記のような実装をする場合のモデル(MSの提唱するデザインパターン)
のようなものはあるのでしょうか?



MSの提唱する非同期のデザインパターンは
IAsyncResultとイベントです。
スレッドはスレッドプールを用いるのを推奨しています。

つまり、非同期な処理をしたいなら、
引用:

正直、C#のThreadを無限ループさせて、排他したキューを実装すれば
自前で実現できますが、


といったことをしないように、
タスクを十分に細かくして、
タスクごとにスレッドプールを使えということです。

引用:

メッセージループをしていて随時メッセージを受信できるスレッド
(=ワーカースレッドではない)を利用してプログラムしたいのですが、
C#ではどのように実装してやればよいのでしょうか?



どうしてもメッセージループを回したいなら
Tdnr_SymさんのおっしゃるようにApplication.Runを使うと思いますが、
「メッセージループをしていて随時メッセージを受信できるスレッドを利用したい」
と思ったことがありません。
常にタスクを実行しているスレッドと通信する場合は
普通に同期オブジェクトを使いますが、
常にタスクを実行するスレッドを作るのもまれで、
数値計算の場合だけです。
普通のアプリで本当に常にタスクを実行しているなら、
重くて熱くてやってられません。

C++でのWindowsアプリケーション開発の知識を
広く適用しすぎに聞こえます。
そもそもスレッド間通信にWindowsメッセージを使うのは
ごく限られた状況だと思います。
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2007-07-11 17:56
こんにちは。

引用:

Makotoさんの書き込み (2007-07-11 16:19) より:
非常に参考になりました。
(興味ですが、Control.Invokeの内部実装ってどうするとみれるんですか?)


Reflectorなどのツールで見ることができますが
ご使用するのが良いか悪いかは、ご自身の判断にお任せします。

引用:

正直、C#のThreadを無限ループさせて、排他したキューを実装すれば
自前で実現できますが、
ライブラリで用意されているのならばそちらを使用したいのです。


非同期メッセージパッシング的な機構が実現できれば
Windowsのメッセージキューじゃなくてもよかったんですね^^;

たしかに自作することはそんなに難しいことではないと思います。
私もある組み込みリアルタイムシステムで、非同期メッセージパッシング機構を
共有メモリ上にリングバッファを作って実現したことがあります。(.NETではないですが)

引用:

C#で上記のような実装をする場合のモデル(MSの提唱するデザインパターン)
のようなものはあるのでしょうか?

または、このようなケースでは皆さんはどのように実装されているのでしょうか?
教えて下さい。



ウィンドウメッセージを使わない非同期メッセージパッシング機構が
.NET Frameworkで提供されているのであれば、私も興味があります。
Makoto
大ベテラン
会議室デビュー日: 2004/03/31
投稿数: 133
投稿日時: 2007-07-11 19:42
To:れい様

回答ありがとうございます。
念のため、再確認させてください。

『スレッドを自作してメンバにオブジェクトを持たせて管理するような実装(私の実装モデル)』ではなく、
『どのスレッドで動作してもよいようなオブジェクト分けをして、CallbackをThreadPoolで実行させなさい(MS実装モデル)』
ってことですよね?

私の認識しているMVCモデルのC(コントローラ)は、デカ過ぎってことですね。
(オブジェクト指向的でない?)

個人的には、.NetFrameworkは謎の部分が多い
(ThreadPool数の制約とかもあったはず)ので、
規模が大きいアプリではあまりCallbackとかクリアに
理解できていない部分は採用したくないなぁ
というのが私の正直な感覚なのです。
(自分のスキル不足ですが...)

一応、MSの推奨モデルということなので、非同期Invokeで実装してみます。
(どのスレッドで実行されるかわからないモデルだと、
 複雑なトランザクションを組むと、デッドロックとかって
 発生頻度上がったりしないのかなぁとやや心配です)

>C++でのWindowsアプリケーション開発の知識を
>広く適用しすぎに聞こえます。
>そもそもスレッド間通信にWindowsメッセージを使うのは
>ごく限られた状況だと思います。

これはご指摘の通りだと思います。
私は、アプリ開発経験がVC++6だけなので
それが常識と思い込んでしまっているんだと思います。

To:Tdnr_Sym様

回答ありがとうございました。

『ウィンドウメッセージを使わない非同期メッセージパッシング機構が
.NET Frameworkで提供されている』かどうかはわかりませんでした。
(おそらく、なさそう?ですね...)

お二人とも、回答ありがとうございました。
勉強になりました。
れい
ぬし
会議室デビュー日: 2005/11/01
投稿数: 346
投稿日時: 2007-07-11 20:23
引用:

Makotoさんの書き込み (2007-07-11 19:42) より:
『スレッドを自作してメンバにオブジェクトを持たせて管理するような実装(私の実装モデル)』ではなく、



えと…
メンバって何のメンバ?
オブジェクトってなんのオブジェクト?
オブジェクトの中にスレッド埋め込んじゃうってこと、かな?
どっかのオブジェクトのメンバにスレッドを持たせるってこと、かな?

すみません、まったくわかりません。

引用:

『どのスレッドで動作してもよいようなオブジェクト分けをして、CallbackをThreadPoolで実行させなさい(MS実装モデル)』
ってことですよね?



いや別にオブジェクトと同期とは関係なくって、
Taskみたいなオブジェクトつくってもいいし、他の方法でもいいし。
でも一度に長時間スレッドを動かしつづけるのはあまりよくなくて、
うまくタスクをわければ
数値計算とか負荷テスト以外ではほとんどなくなるはず。

もし一つのスレッドをずっと動かし続けたいなら自分でスレッド作ったほうが楽。

あとCallbackはThreadPoolのスレッドとは限らないです。
呼び出し元スレッドの場合もあるし。
ぜんぜん関係ない第3のスレッドの場合もあるし。

引用:

私の認識しているMVCモデルのC(コントローラ)は、デカ過ぎってことですね。
(オブジェクト指向的でない?)



MVCってModel View ControllerのMVC?
スレッドの話じゃなかったっけ?

メインじゃないスレッドのほうもViewがあるなら
普通にそのスレッドでForm作ればいいのでは?

引用:

個人的には、.NetFrameworkは謎の部分が多い
(ThreadPool数の制約とかもあったはず)ので、
規模が大きいアプリではあまりCallbackとかクリアに
理解できていない部分は採用したくないなぁ
というのが私の正直な感覚なのです。



理解できていない部分を採用しないのは正しいと思いますが…。
「理解できていない部分を採用しない」且つ「.NetFrameworkは謎の部分が多い」
なら.Net Frameworkを使わないのが最良の解決法なのでは?

引用:

一応、MSの推奨モデルということなので、非同期Invokeで実装してみます。
(どのスレッドで実行されるかわからないモデルだと、
 複雑なトランザクションを組むと、デッドロックとかって
 発生頻度上がったりしないのかなぁとやや心配です)



「どのスレッドで実行されるかわかってるモデル」を使えば気にしなくて良かったことを、
「どのスレッドで実行されるかわからないモデル」では気にしなければならなくなるかもしれませんが、
それは本来マルチスレッドプログラミングでは
解決しなければならないはずの問題だと思いますよ。
それをシングルスレッド風に処理してたから問題なかっただけで。
その分ウェイトがあってパフォーマンスが落ちてたのでは?


1

スキルアップ/キャリアアップ(JOB@IT)