C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[10]: Invoke関係の理解


(過去ログ 127 を表示中)

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■75647 / inTopicNo.1)  Invoke関係の理解
  
□投稿者/ kiku (43回)-(2015/04/20(Mon) 11:46:04)

分類:[C#] 

環境:VS2013、C#、Formアプリ、ライブラリ

やりたいこと:
 ライブラリを利用する利用者側に、ライブラリ内でスレッドを生成していることを
 できるだけ意識させず、スレッド内の情報を利用者側に提供したい。

現在、下記のソースのように、int型の変数を1つ返すイベントを定義し、
スレッド内からフォームへイベントを発生させています。
そのイベント内からtextBox1にアクセスするとエラーになるため、
Invokeを利用しています。

このInvokeを利用者側が実装しなくても利用できるようにしたいのですが、
それを考えている最中にそもそもどのような理屈で動作しているのかわからないくなってしまいました。
まだまだ小生の理解が足りていないと思っています。
そこで下記質問させてください。

質問1
 1回目のClass1_Countは別スレッドから同期式(event)で呼び出しているので
 別スレッド(work)で実行されている?

質問2
 1回目のClass1_CountのCountEventArgs eは、別スレッド内で
 newしているので別スレッドの持ち物?

質問3
 eventをやめて非同期式でデリゲートを経由すれば、
 Class1_CountはUIスレッドで実行される?

質問4
 InvokeはメインスレッドでClass1_Countを実行するメソッド?

質問5
 どのような実装が一般的なのでしょうか?


==下記ソースは問題なく動作しています==

using System.Threading;
namespace ClassLibrary1
{
    public class CountEventArgs : EventArgs
    {
        public int eCount;
    }
    public class Class1
    {
        public delegate void CountEventHandler(object sender, CountEventArgs e);
        public event CountEventHandler Count;
        public void Start()
        {
            Thread t1 = new Thread(new ThreadStart(work));
            t1.Start();
        }
        public void work()
        {
            int wCount = 100;
            if (Count != null)
            {
                CountEventArgs e = new CountEventArgs();
                e.eCount = wCount;
                Count(this, e);
            }
        }
    }
}

    public partial class Form1 : Form
    {
        ClassLibrary1.Class1 c1;
        private void button1_Click(object sender, EventArgs e)
        {
            c1 = new ClassLibrary1.Class1();
            c1.Count += new ClassLibrary1.Class1.CountEventHandler(Class1_Count);
            c1.Start();
        }
        public void Class1_Count(object sender, ClassLibrary1.CountEventArgs e)
        {
            if (this.InvokeRequired)
            {
                ClassLibrary1.Class1.CountEventHandler dlgt = new ClassLibrary1.Class1.CountEventHandler(Class1_Count);
                this.Invoke(dlgt, new object[] { sender, e });
                return;
            }
            textBox1.Text = e.eCount.ToString();
        }
    }

引用返信 編集キー/
■75648 / inTopicNo.2)  Re[1]: Invoke関係の理解
□投稿者/ Hongliang (301回)-(2015/04/20(Mon) 12:10:09)
> 質問1
>  1回目のClass1_Countは別スレッドから同期式(event)で呼び出しているので
>  別スレッド(work)で実行されている?
1回目というのは、this.InvokeからではなくClass1::workから直接呼び出されたとき、という意味でしょうか。
それならばYesです。

> 質問2
>  1回目のClass1_CountのCountEventArgs eは、別スレッド内で
>  newしているので別スレッドの持ち物?
通常のオブジェクトはスレッドの持ち物という概念を持ちません。EventArgsも、それから派生したCountEventArgsもそうです。
あらゆるスレッドが自由にアクセスできます。アクセスの同期とかはオブジェクトの使用者が考えなければなりません。

> 質問3
>  eventをやめて非同期式でデリゲートを経由すれば、
>  Class1_CountはUIスレッドで実行される?
関係ないです。

> 質問4
>  InvokeはメインスレッドでClass1_Countを実行するメソッド?
そのコントロールが属するスレッド(一般的な作りをしていればメインスレッドになります)で指定されたデリゲートを実行します。

> 質問5
>  どのような実装が一般的なのでしょうか?
今時であれば、明示的にThreadを使うのではなく、Taskで動作させるのでは。経過通知にはSystem.Progress<T>辺りで。
プリミティブには、SynchronizationContextを保持しておいて、イベントのコールバックはそれを経由してPostする形式でしょうか。
引用返信 編集キー/
■75649 / inTopicNo.3)  Re[2]: Invoke関係の理解
□投稿者/ kiku (44回)-(2015/04/20(Mon) 13:06:51)
No75648 (Hongliang さん) に返信

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

>>質問1
>> 1回目のClass1_Countは別スレッドから同期式(event)で呼び出しているので
>> 別スレッド(work)で実行されている?
> 1回目というのは、this.InvokeからではなくClass1::workから直接呼び出されたとき、という意味でしょうか。
> それならばYesです。

理解しました。

>>質問2
>> 1回目のClass1_CountのCountEventArgs eは、別スレッド内で
>> newしているので別スレッドの持ち物?
> 通常のオブジェクトはスレッドの持ち物という概念を持ちません。EventArgsも、それから派生したCountEventArgsもそうです。
> あらゆるスレッドが自由にアクセスできます。アクセスの同期とかはオブジェクトの使用者が考えなければなりません。

理解しました。

>>質問3
>> eventをやめて非同期式でデリゲートを経由すれば、
>> Class1_CountはUIスレッドで実行される?
> 関係ないです。

「関係ない」という言葉から、深く考えた結果、
確か、非同期メソッドはスレッドプール経由で実行されると
聞いたことがあるため、別スレッドからアクセスされるという意味では
同じであるため、関係ないということでしょうか?

>>質問4
>> InvokeはメインスレッドでClass1_Countを実行するメソッド?
> そのコントロールが属するスレッド(一般的な作りをしていればメインスレッドになります)で指定されたデリゲートを実行します。

理解しました。

>>質問5
>> どのような実装が一般的なのでしょうか?
> 今時であれば、明示的にThreadを使うのではなく、Taskで動作させるのでは。経過通知にはSystem.Progress<T>辺りで。
> プリミティブには、SynchronizationContextを保持しておいて、イベントのコールバックはそれを経由してPostする形式でしょうか。

この点は知識がないため、勉強してみます。

引用返信 編集キー/
■75650 / inTopicNo.4)  Re[3]: Invoke関係の理解
□投稿者/ Hongliang (302回)-(2015/04/20(Mon) 13:18:04)
> >>質問3
> >> eventをやめて非同期式でデリゲートを経由すれば、
> >> Class1_CountはUIスレッドで実行される?
確認し忘れていましたが、この「非同期式でデリゲートを経由」というのは
this.Count.BeginInvoke(...);
という理解で良いんですよね?

> 「関係ない」という言葉から、深く考えた結果、
> 確か、非同期メソッドはスレッドプール経由で実行されると
> 聞いたことがあるため、別スレッドからアクセスされるという意味では
> 同じであるため、関係ないということでしょうか?
そうですね。
Delegate::BeginInvokeは、特定のスレッドでデリゲートを実行するような機能を持っていません。
引用返信 編集キー/
■75651 / inTopicNo.5)  Re[4]: Invoke関係の理解
□投稿者/ kiku (45回)-(2015/04/20(Mon) 13:34:33)
No75650 (Hongliang さん) に返信

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

>>>>質問3
>>>> eventをやめて非同期式でデリゲートを経由すれば、
>>>> Class1_CountはUIスレッドで実行される?
> 確認し忘れていましたが、この「非同期式でデリゲートを経由」というのは
> this.Count.BeginInvoke(...);
> という理解で良いんですよね?

そのとおりです。

>>「関係ない」という言葉から、深く考えた結果、
>>確か、非同期メソッドはスレッドプール経由で実行されると
>>聞いたことがあるため、別スレッドからアクセスされるという意味では
>>同じであるため、関係ないということでしょうか?
> そうですね。
> Delegate::BeginInvokeは、特定のスレッドでデリゲートを実行するような機能を持っていません。

なるほど、理解しました。

> 今時であれば、明示的にThreadを使うのではなく、Taskで動作させるのでは。経過通知にはSystem.Progress<T>辺りで。
> プリミティブには、SynchronizationContextを保持しておいて、イベントのコールバックはそれを経由してPostする形式でしょうか。

この辺りをもう少し理解してから「解決済み」にしたいと思っています。

引用返信 編集キー/
■75657 / inTopicNo.6)  Re[5]: Invoke関係の理解
□投稿者/ kiku (46回)-(2015/04/21(Tue) 10:45:39)

>>今時であれば、明示的にThreadを使うのではなく、Taskで動作させるのでは。経過通知にはSystem.Progress<T>辺りで。
>>プリミティブには、SynchronizationContextを保持しておいて、イベントのコールバックはそれを経由してPostする形式でしょうか。
>
> この辺りをもう少し理解してから「解決済み」にしたいと思っています。

この方法を勉強中なのですが、
なかなか情報が少なく、まだ動かせていない状況です。
小生の技術力では時間がかかりそうなので
この方法は別途継続的に勉強することとしました(別スレッドで質問したい)。

この方法以外の別解はないでしょうか?
「DLLの利用者側に、invokeせずにスレッド内の情報を
 利用できるようにしたい。」
.NET3.5の技術でOKです。

引用返信 編集キー/
■75661 / inTopicNo.7)  Re[6]: Invoke関係の理解
□投稿者/ daive (50回)-(2015/04/21(Tue) 11:21:59)
>やりたいこと:
> ライブラリを利用する利用者側に、ライブラリ内でスレッドを生成していることを
> できるだけ意識させず、スレッド内の情報を利用者側に提供したい。

>この方法以外の別解はないでしょうか?
>「DLLの利用者側に、invokeせずにスレッド内の情報を
> 利用できるようにしたい。」
>.NET3.5の技術でOKです。
想定速度、アクセス頻度、データ量、など不明点多数です。
おこないたい事を、具体的に書かれないと、
外部の人間には、貴方のPCの画面も、貴方の頭の中も、
のぞき見する事はできません。

例えば、
1.Windowsのサービスとして実装する。
2.サーバーモデルにする。WCFなど。
3.安直な処では、ファイルでのデータ交換。RAM-DISKベースであれば、高速。
  メモリマップドファイルでのデータ交換。
  データベース経由での、データ交換。記録も残せる。


引用返信 編集キー/
■75663 / inTopicNo.8)  Re[7]: Invoke関係の理解
□投稿者/ Hongliang (303回)-(2015/04/21(Tue) 11:50:58)
// daiveさんのはどこかの誤爆かな?

ほかには、System.Timers.Timerがやっているような手法がありますね。
これは、SynchronizingObjectというISynchronizeInvoke型のプロパティを公開して、利用者にこれを設定させるというものです。
ISynchronizeInvokeインターフェイスは、たとえばControlクラスが実装しています。

// このスレッドで言うClass1をComponentから派生させデザイナで配置するようにすれば、SyncrhonizingObjectプロパティを自動的に設定させるようにすることもできますが、説明は略。
引用返信 編集キー/
■75665 / inTopicNo.9)  Re[7]: Invoke関係の理解
□投稿者/ kiku (47回)-(2015/04/21(Tue) 12:17:04)
No75661 (daive さん) に返信
> 想定速度、アクセス頻度、データ量、など不明点多数です。
> おこないたい事を、具体的に書かれないと、
> 外部の人間には、貴方のPCの画面も、貴方の頭の中も、
> のぞき見する事はできません。
>
> 例えば、
> 1.Windowsのサービスとして実装する。
> 2.サーバーモデルにする。WCFなど。
> 3.安直な処では、ファイルでのデータ交換。RAM-DISKベースであれば、高速。
>   メモリマップドファイルでのデータ交換。
>   データベース経由での、データ交換。記録も残せる。

できるだけ説明しているつもりですが
まだまだ説明不足のようです。
具体的に何がわからないのかご質問いただければご解答します。

引用返信 編集キー/
■75666 / inTopicNo.10)  Re[8]: Invoke関係の理解
□投稿者/ kiku (48回)-(2015/04/21(Tue) 12:21:32)
No75663 (Hongliang さん) に返信

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

> ほかには、System.Timers.Timerがやっているような手法がありますね。
> これは、SynchronizingObjectというISynchronizeInvoke型のプロパティを公開して、利用者にこれを設定させるというものです。
> ISynchronizeInvokeインターフェイスは、たとえばControlクラスが実装しています。
>
> // このスレッドで言うClass1をComponentから派生させデザイナで配置するようにすれば、SyncrhonizingObjectプロパティを自動的に設定させるようにすることもできますが、説明は略。

この方法ならできそうです。

ISynchronizeInvokeのオブジェクトを受け取るプロパティ(受け取れれば良い)を作成し、
そこへ利用者にコントロール(またはフォーム)のオブジェクトを登録してもらう。
クラス側ではこのプロパティが nullでなく、InvokeRequiredがtrueなら、
Invokeでイベントを呼び出す。

この方向でサンプルを作ってみます。

引用返信 編集キー/
■75668 / inTopicNo.11)  Re[8]: Invoke関係の理解
□投稿者/ shu (735回)-(2015/04/21(Tue) 12:47:45)
2015/04/21(Tue) 12:50:38 編集(投稿者)

No75665 (kiku さん) に返信
> ■No75661 (daive さん) に返信

・・・

> できるだけ説明しているつもりですが
> まだまだ説明不足のようです。
> 具体的に何がわからないのかご質問いただければご解答します。

質問されているのはkikuさんであり、daiveさんは質問方法に対する助言を
しただけなのでは?『ご質問』は通常回答者がするものではありません。



引用返信 編集キー/
■75669 / inTopicNo.12)  Re[9]: Invoke関係の理解
□投稿者/ kiku (49回)-(2015/04/21(Tue) 13:42:21)
なんとか動作するサンプルを作ることができました。
ありがとうございました。

using System.Threading;
namespace ClassLibrary1
{
    public class CountEventArgs : EventArgs
    {
        public int eCount;
    }
    public class Class1
    {
        public delegate void CountEventHandler(object sender, CountEventArgs e);
        public event CountEventHandler Count;
        private System.ComponentModel.ISynchronizeInvoke _SynchronizingObject;
        public System.ComponentModel.ISynchronizeInvoke SynchronizingObject
        {
            get
            {
                return _SynchronizingObject;
            }
            set
            {
                _SynchronizingObject = value;
            }
        }
        public void Start()
        {
            Thread t1 = new Thread(new ThreadStart(work));
            t1.Start();
        }
        public void work()
        {
            int wCount = 100;
            if (Count != null)
            {
                CountEventArgs e = new CountEventArgs();
                e.eCount = wCount;
                _SynchronizingObject.Invoke(Count, new object[] { this, e });
            }
        }
    }
}

namespace test02
{
    public partial class Form1 : Form
    {
        ClassLibrary1.Class1 c1;
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            c1 = new ClassLibrary1.Class1();
            c1.SynchronizingObject = this;
            c1.Count += new ClassLibrary1.Class1.CountEventHandler(Class1_Count);
            c1.Start();
        }
        public void Class1_Count(object sender, ClassLibrary1.CountEventArgs e)
        {
            textBox1.Text = e.eCount.ToString();
        }
    }
}

解決済み
引用返信 編集キー/
■75670 / inTopicNo.13)  Re[9]: Invoke関係の理解
□投稿者/ kiku (50回)-(2015/04/21(Tue) 13:50:37)
> 質問されているのはkikuさんであり、daiveさんは質問方法に対する助言を
> しただけなのでは?『ご質問』は通常回答者がするものではありません。

確かにそうですね。
daiveさん、shuさん大変失礼いたしました。
m(_ _)m

引用返信 編集キー/
■75671 / inTopicNo.14)  Re[10]: Invoke関係の理解
□投稿者/ kiku (51回)-(2015/04/21(Tue) 13:51:28)
解決済みつけ忘れです。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -