DOBON.NETプログラミング道掲示板

■34616 / 親記事)  親スレッドへ処理の移譲
  
□投稿者/ あばば無人君 一般人(18回)-(2021/01/16(Sat) 17:02:39)
  • アイコン環境/言語:[Windows10(1909) 64bit、.Net 5.0、C#] 
    分類:[.NET] 

    いつも本掲示板でお勉強させていただいております。

    さてタイトルの件ですが、親スレッドAが居てそこから別スレッドBを
    生成→開始します。なお生成時にBに対してAのthisを渡しています。

    そしてBの処理が終了後にAから渡されたthisの関数をコールしますが
    当然その関数はBのスレッドの処理として動作します。

    これをAのスレッドとして操作させるにはどうしたらよいでしょうか?
    ちなみにGUIアプリケーションではありません。

    ご存知の方がいらっしゃいましたらぜひご教授いただきたいです。

マルチポストを報告
違反を報告
引用返信 削除キー/
■34617 / ResNo.1)  Re[1]: 親スレッドへ処理の移譲
□投稿者/ Azulean 大御所(521回)-(2021/01/16(Sat) 17:11:18)
  • アイコンNo34616に返信(あばば無人君さんの記事)
    > さてタイトルの件ですが、親スレッドAが居てそこから別スレッドBを
    > 生成→開始します。なお生成時にBに対してAのthisを渡しています。

    ご存知かもしれませんが、「A の this」は「スレッドと関係ないオブジェクト」です。
    このため、以下の結果になります。

    > そしてBの処理が終了後にAから渡されたthisの関数をコールしますが
    > 当然その関数はBのスレッドの処理として動作します。


    -----

    > これをAのスレッドとして操作させるにはどうしたらよいでしょうか?
    > ちなみにGUIアプリケーションではありません。

    GUI アプリケーションでメッセージループが回っているスレッドなら Control.BeginInvoke や SynchronizationContext.Post が通用しますが、それが使えない環境では「自分で作る」しかありません。

    A スレッドの中でループを書いて、他のスレッドから「何か」登録されたら処理する…といったようなものです。

    たとえば、ConcurrentQueue を使う仕組みです。

    ・A スレッドは定期的に ConcurrentQueue を確認する。
    ・何か結果が登録されていれば処理し、そうでなければ別のことをするか、一定時間待つ
    ・B スレッドなどの子スレッドは処理が終わったら、ConcurrentQueue に結果を登録する

違反を報告
引用返信 削除キー/
■34618 / ResNo.2)  Re[2]: 親スレッドへ処理の移譲
□投稿者/ あばば無人君 一般人(20回)-(2021/01/16(Sat) 17:58:23)
  • アイコンAzuleanさん、ご返信ありがとうございます。

    > ご存知かもしれませんが、「A の this」は「スレッドと関係ないオブジェクト」です。

    はい、存じております。ですので最初の投稿で「当然」と記載しております。


    > それが使えない環境では「自分で作る」しかありません。

    う〜ん、それしかないのですね。
    私が知らないだけで、言語レベルでできないかと期待したのですが…。

    実はフレームワークを作成中で、Aの方はそのフレームワークを使う
    開発者側のスレッド、Bがフレームワーク側の処理、という感じです。
    ですのでAの方には負担が無いようにしたいのです。

    少し検討してみます。ご回答ありがとうございました。
    本件はこれで解決済みとさせていただきます。

違反を報告
引用返信 削除キー/
■34619 / ResNo.3)  Re[3]: 親スレッドへ処理の移譲
□投稿者/ あばば無人君 一般人(21回)-(2021/01/16(Sat) 17:59:24)
  • アイコンすみません、解決済みにチェックをしていませんでした。
    今度こそ!!

解決み!
違反を報告
引用返信 削除キー/
■34620 / ResNo.4)  Re[3]: 親スレッドへ処理の移譲
□投稿者/ Azulean 大御所(522回)-(2021/01/16(Sat) 19:12:29)
  • アイコンNo34618に返信(あばば無人君さんの記事)
    > 私が知らないだけで、言語レベルでできないかと期待したのですが…。

    勝手に動かれたら制御しづらいだけですよ。

    GUI のメインスレッドへの Post/BeginInvoke は、イベントを抜けたあとなど、自分の制御内から抜けたときに処理されるので、自分のコードを実行中に割り込まれることがありません。

    対して、自分で作ったスレッドの場合、スレッドが生きている間は自分のコードしか実行されません。
    その状況で「言語レベルで対応」となると、「いわゆる割り込み」です。
    「このコード実行中は割り込まないで」みたいな制御を作っていくことになるので難しくなると思いますよ…。

    > 実はフレームワークを作成中で、Aの方はそのフレームワークを使う
    > 開発者側のスレッド、Bがフレームワーク側の処理、という感じです。
    > ですのでAの方には負担が無いようにしたいのです。

    それは無理だと思います。
    できたとして以下のようなことでしょう。

    <案1>
    「Application.DoEvents」のように「待っている処理があったら処理する」みたいなメソッドを提供する。

    <案2>
    スレッド A の根底のメッセージループなものを提供し、A はイベントドリブンで動くようにする。
    (スレッド A の主導権をフレームワークが握る。つまり、Windows の GUI アプリケーションと同じようなことをする)
解決み!
違反を報告
引用返信 削除キー/
■34621 / ResNo.5)  Re[4]: 親スレッドへ処理の移譲
□投稿者/ あばば無人君 一般人(22回)-(2021/01/20(Wed) 09:24:43)
  • アイコンAzuleanさん、ご返信ありがとうございます。

    ご回答いただいた<案2>ですが、実はスレッドAの方はその作りです。
    別装置などから送信された電文をConcurrentQueueに積んで、スレッドAで
    それを取り出して処理するといった実装です。

    そして、別装置などから想定している電文が送信されてこない場合の
    タイムアウト処理の起動をスレッドBが行っている感じです。

    やはりスレッドBがConcurrentQueueにタイムアウト用の電文を積み、
    スレッドAでそれを処理させる方法しかないのですね…。
    GUIアプリケーションのBeginInvoke的なことができないかを
    探していたのですが諦めます。

    本件はこれで解決済みとさせていただきます。
    何度も返信を下さり本当にありがとうございました。

解決み!
違反を報告
引用返信 削除キー/
■34629 / ResNo.6)  Re[5]: 親スレッドへ処理の移譲
□投稿者/ Azulean 大御所(524回)-(2021/01/20(Wed) 23:07:46)
  • アイコン2021/01/20(Wed) 23:12:40 編集(投稿者)

    No34621に返信(あばば無人君さんの記事)
    > ご回答いただいた<案2>ですが、実はスレッドAの方はその作りです。
    > 別装置などから送信された電文をConcurrentQueueに積んで、スレッドAで
    > それを取り出して処理するといった実装です。

    私が書いたイベントドリブンとは、スレッド A の根元のコード(ループ)をフレームワークが担う…ということです。認識が合っていればよいのですが…。
    Windows Forms でいえば、Application.Run 自体をフレームワークが作るということです。

    > GUIアプリケーションのBeginInvoke的なことができないかを
    > 探していたのですが諦めます。

    BeginInvoke の実態は「実行予定のキューに追加し、ウィンドウメッセージを飛ばして通知する」です。
    そして、Application.Run の中のメッセージループがそのウィンドウメッセージを取り出した際に、キューに積まれているデリゲートを実行します。

    (Application.Run イメージ)
    while (true)
    {
    // 新規メッセージ取り出し (メッセージがないなら取り出せるまで待つ)

    // メッセージを Form や Control に割り振り、Form や Control がイベントを発行する
    // ただし、そのメッセージがBeginInvoke/Invokeのものであれば、キューを確認してデリゲートを実行する

    // 次のメッセージを待つため、ループを繰り返す
    }
    -----

    このため、言語的に実現しているものではなく、Windows Forms というフレームワークが実現しているものです。

    同じようなものを求めるなら、スレッド A の根底となる処理(ループ)をあなたのフレームワークで提供するしかないです。

    ※認識がずれている可能性があったので返信した次第ですので、認識が合っていれば、返信は不要です。
解決み!
違反を報告
引用返信 削除キー/
■34631 / ResNo.7)  Re[6]: 親スレッドへ処理の移譲
□投稿者/ あばば無人君 一般人(23回)-(2021/01/21(Thu) 10:09:51)
  • アイコンAzuleanさん、ご返信ありがとうございます。

    > ※認識がずれている可能性があったので返信した次第ですので、認識が合っていれば、返信は不要です。

    認識ずれの配慮、ありがとうございます。

    ちゃんと意図が伝わるか不安だったので投稿の説明を
    シンプルにしたつもりでしたが、それが良くなかったです。
    正確に記載します。

    まずスレッドAと記載していたものですが、こちらは開発者のクラスが
    フレームワーク内のクラス(抽象)を継承しており、その親クラスの挙動が
    Azuleanさんが記載したwhile文の様な挙動をしております。

    親クラスを一部抜粋
    public abstract class ParentClass
    {
      public BlockingCollection<MessageData> que =
                 new BlockingCollection<MessageData>();

      void MainLoop()
      {
        while
        {
          MessageData data;
          que.TryTake(out data, Timeout.Infinite)

          this.MessageReceive(data);
        }
      }

      internal abstract void MessageReceive(MessageData data);
    }

    開発者は上記のMessageReceiveをオーバーライドして処理を実装しており
    その処理中で次電文の受信待ちタイマーを張るのですが、そのタイマーが
    スレッドBと記載していた物です。

    次電文を時間内に受信できなかった時にスレッドBはタイムアウト処理として
    スレッドAが渡したthisにある関数をコールしている、という動きです。
    これをスレッドAの処理として動かしたかったというのが目的でした。

    上記の通りAzuleanさんが記載して下さった様な挙動となっていますので
    認識ずれは無いかと思います。
    開発者側にはMessageReceive関数の中でタイムアウトの処理を実装させる
    ルールとします。

    何度も丁寧に説明していただき本当にありがとうございました。

解決み!
違反を報告
引用返信 削除キー/



スレッド内ページ移動 / << 0 >>

このスレッドに書きこむ

Mode/  Pass/


- Child Tree -