DOBON.NETプログラミング道掲示板
(現在 過去ログ2 を表示中)

[ 最新記事及び返信フォームをトピックトップへ ]

■33668 / inTopicNo.1)  Threading.Threadで戻り値を取得したい
  
□投稿者/ ゆう 一般人(1回)-(2017/08/31(Thu) 11:20:08)
  • アイコン環境/言語:[Framework 2.0] 
    分類:[.NET] 

    Threading.Threadで呼び出した関数の戻り値を取得したいのですが
    何か方法はありますか?
引用返信 削除キー/
■33669 / inTopicNo.2)  Re[1]: Threading.Threadで戻り値を取得したい
□投稿者/ YuO 一般人(1回)-(2017/08/31(Thu) 13:31:06)
  • アイコンNo33668に返信(ゆうさんの記事)
    > Threading.Threadで呼び出した関数の戻り値を取得したいのですが
    > 何か方法はありますか?

    戻り値も何も,Thread.Startで呼び出されるデリゲートは戻り値を返さない(返せない)と思うのですが。
    何らかの戻り値があるのであれば,ThreadよりもTaskを考えてみてはどうでしょうか。
引用返信 削除キー/
■33670 / inTopicNo.3)  Re[1]: Threading.Threadで戻り値を取得したい
□投稿者/ 魔界の仮面弁士 大御所(1078回)-(2017/08/31(Thu) 13:42:45)
  • アイコンNo33668に返信(ゆうさんの記事)
    > Threading.Threadで呼び出した関数の戻り値を取得したいのですが
    > 何か方法はありますか?

    (案1)スレッド処理を行うクラス自身に、
     処理結果を格納するためのプロパティを用意しておく。
    https://msdn.microsoft.com/ja-jp/library/cc404925.aspx#vbtchasyncprocvbanchor8


    (案2)BackgroundWorker クラスの RunWorkerCompleted イベントを真似て、
     処理完了を通知するデリゲートを用意し、処理結果を引数として渡す。
    http://d.hatena.ne.jp/shunsuk/20070613/1181730536


    (案3).NET のバージョンを上げて、Await キーワードで受け取るようにする。
    https://msdn.microsoft.com/ja-jp/library/hh524395.aspx
引用返信 削除キー/
■33671 / inTopicNo.4)  Re[2]: Threading.Threadで戻り値を取得したい
□投稿者/ ゆう 一般人(2回)-(2017/08/31(Thu) 15:41:54)
  • アイコン
    No33670に返信(魔界の仮面弁士さんの記事)
    
    ご回答ありがとうございます
    
    案2を実装しようと思い自分なりにコードをVBに変えたのですが文法エラーが直りません
    
    書き方をご指摘していただけないでしょうか?
    
    Public Class ThreadBuilder
        Public Delegate Function MethodDelegate(Of T)() As T
        Public Delegate Sub CallbackDelegate(Of T)(ReturnValue As T)
    
        Public Shared Function NewThread(Of T)(Method As MethodDelegate(Of T), CallBack As CallbackDelegate(Of T)) As Threading.Thread
            Return New Threading.Thread(New Threading.ParameterizedThreadStart( _
          Sub()
            ~~~~~→Visual Basic 9.0はこのラムダ式をサポートしていません
                Dim Ret As T = Method()
                If CallBack IsNot Nothing Then CallBack(Ret)
            End Sub))
        End Function
    End Class
    
    Public Class Program
        Sub Main(Args() As String)
            Dim Val1 As Integer = 1
            Dim Val2 As Integer = 2
            Dim Ans As Integer = 0
    
            Dim NewThread as ThreadBuilder.NewThread(of integer)( _
                Sub()
                ~~~~~→配列の指定を、型指定子に記述することはできません。
                     Return Val1 + Val2
                End Sub, _
                Sub()
                ~~~~~→上と同じ
                     Ans = returnValue
                End Sub
        End Sub
    End Class
    

引用返信 削除キー/
■33672 / inTopicNo.5)  Re[3]: Threading.Threadで戻り値を取得したい
□投稿者/ 魔界の仮面弁士 大御所(1079回)-(2017/08/31(Thu) 17:02:40)
  • アイコンNo33671に返信(ゆうさんの記事)
    > 案2を実装しようと思い自分なりにコードをVBに変えたのですが文法エラーが直りません

    言語指定がありませんでしたが、今回は Visual Basic で実装されるのですね。


    > Public Class Program
    > Sub Main(Args() As String)

    これはコンソールアプリケーションでしょうか?
    だとしたら、VB で書く場合は、

     Public Class Program
      Shared Sub Main(Args() As String)

    もしくは

     Public Moudle Program     '既定では Module1 ですが名前は任意
      Sub Main(Args() As String)  '既定では 引数なし

    にしなければなりません。
    ※プロジェクトのプロパティ「アプリケーション」タブの『スタートアップ オブジェクト』も確認を。



    > →Visual Basic 9.0はこのラムダ式をサポートしていません

    9.0 ということは、VB2008 をお使いでしょうか。
    であればラムダ式を使わずに、AddressOf で記述してみてください。


    .NET Framework 2.0 であっても、Sub による複数行ラムダ式は使えますが、
    コンパイラは 10.0 (VB2010) 以降が必要になります。

    VB2008 で使えるラムダ式は、Function による単一行ラムダのみであり、
    複数行ラムダはおろか、Sub のラムダ式さえサポートしていません。


    Public Class ThreadBuilder
     Public Delegate Function MethodDelegate(Of T)() As T
     Public Delegate Sub CallbackDelegate(Of T)(ByVal ReturnValue As T)
     
     Public Shared Function NewThread(Of T)(ByVal Method As MethodDelegate(Of T), ByVal CallBack As CallbackDelegate(Of T)) As Threading.Thread
      Dim act As New Worker(Of T)(Method, CallBack)
      Return New Threading.Thread(New Threading.ParameterizedThreadStart(AddressOf act.Invoke))
     End Function
     
     Private Class Worker(Of T)
      Private _Method As MethodDelegate(Of T)
      Private _CallBack As CallbackDelegate(Of T)
      Public Sub New(ByVal Method As MethodDelegate(Of T), ByVal CallBack As CallbackDelegate(Of T))
       _Method = Method
       _CallBack = CallBack
      End Sub
      Public Sub Invoke()
       Dim Ret As T = _Method()
       If _CallBack IsNot Nothing Then
        _CallBack(Ret)
       End If
      End Sub
     End Class
    End Class
引用返信 削除キー/
■33673 / inTopicNo.6)  Re[4]: Threading.Threadで戻り値を取得したい
□投稿者/ 魔界の仮面弁士 大御所(1080回)-(2017/08/31(Thu) 18:08:47)
  • アイコンNo33672に追記(魔界の仮面弁士の記事)
    > 9.0 ということは、VB2008 をお使いでしょうか。
    > であればラムダ式を使わずに、AddressOf で記述してみてください。

    VB2005 / 2008 の場合は、Thread を直接扱うよりも、
    BackgroundWorker を使ったほうが楽かもしれません。

    VB2012 以降は Task で。
引用返信 削除キー/
■33674 / inTopicNo.7)  Re[4]: Threading.Threadで戻り値を取得したい
□投稿者/ ゆう 一般人(3回)-(2017/09/01(Fri) 09:43:34)
  • アイコンNo33672に返信(魔界の仮面弁士さんの記事)

    ありがとうございます

    Class Programの方も記述の仕方がわかりません
    お手数ですが教えてください
引用返信 削除キー/
■33676 / inTopicNo.8)  Re[5]: Threading.Threadで戻り値を取得したい
□投稿者/ 魔界の仮面弁士 大御所(1082回)-(2017/09/01(Fri) 11:23:42)
  • アイコンNo33674に返信(ゆうさんの記事)
    > Class Programの方も記述の仕方がわかりません

    先の案2 は、匿名メソッドや複数行ラムダの利用を前提としたヘルパークラスです。

    それらが使えない VB2008 から使おうとすると、受け渡し用のメソッドを
    個別に用意しなければならないので、むしろ二度手間になる気がします。

    最近のバージョンであれば、Task を使って簡単に書けるのですけれどね…。


    > お手数ですが教えてください

    変換の仕方は、ThreadBuilder の場合と同じです。

    ただ、 No33672 のコードは VB2008 以上で無いと動作しませんので、
    今回は VB2005 でも使える形に書き換えてみました。


    '--------------------------------------------------------
    'Module1.vb
    '--------------------------------------------------------
    Imports System.Threading
    Module Module1
      Sub Main()
        'ラムダ式が使えないので、受け渡し用のクラスを用意しなければならない。
        Dim wk As New Worker(1, 2)

        'スレッド生成
        Dim newThread As Thread = ThreadBuilder.NewThread(Of Integer)(AddressOf wk.Method, AddressOf wk.CallBack)

        'スレッド開始
        newThread.Start()

        'メインスレッドの処理

        'サブスレッドの完了待ち
        newThread.Join()
        Console.WriteLine(wk.ans)
        Console.ReadLine()
      End Sub

      Private Class Worker
        Private val1, val2 As Integer
        Public ans As Integer

        Public Sub New(ByVal val1 As Integer, ByVal val2 As Integer)
          Me.val1 = val1
          Me.val2 = val2
        End Sub

        ''' <summary>
        ''' 別スレッドに実行させたい処理
        ''' </summary>
        Friend Function Method() As Integer
          Return Me.val1 + Me.val2
        End Function

        ''' <summary>
        ''' スレッド完了後に戻り値をセットする処理
        ''' </summary>
        Friend Sub CallBack(ByVal returnValue As Integer)
          Me.ans = returnValue
        End Sub
      End Class
    End Module


    '--------------------------------------------------------
    'ThreadBuilder.vb
    '--------------------------------------------------------
    Imports System.Threading
    Public Class ThreadBuilder
      Public Delegate Function MethodDelegate(Of T)() As T
      Public Delegate Sub CallbackDelegate(Of T)(ByVal ReturnValue As T)

      Public Shared Function NewThread(Of T)(ByVal Method As MethodDelegate(Of T), ByVal CallBack As CallbackDelegate(Of T)) As Thread
        Dim act As New Worker(Of T)(Method, CallBack)
        Return New Thread(New Threading.ParameterizedThreadStart(AddressOf act.Invoke))
      End Function

      Private Class Worker(Of T)
        Private Method As MethodDelegate(Of T)
        Private Callback As CallbackDelegate(Of T)
        Public Sub New(ByVal Method As MethodDelegate(Of T))
          Me.New(Method, Nothing)
        End Sub
        Public Sub New(ByVal Method As MethodDelegate(Of T), ByVal CallBack As CallbackDelegate(Of T))
          Me.Method = Method
          Me.Callback = CallBack
        End Sub
        Public Sub Invoke(ByVal CallBack As Object)
          Dim cb As CallbackDelegate(Of T) = TryCast(CallBack, CallbackDelegate(Of T))
          If cb Is Nothing Then
            cb = Me.Callback
          End If
          Invoke(cb)
        End Sub
        Private Sub Invoke(ByVal CallBack As CallbackDelegate(Of T))
          Dim Ret As T = Method()
          If CallBack IsNot Nothing Then
            CallBack(Ret)
          End If
        End Sub
      End Class
    End Class





    ローカル変数ではなく、フィールド変数でも構わなければ、下記のように単純化することもできます。
    どの変数をどのスレッドが利用するのかを把握している必要があるので、

    'Module1.vb
    Imports System.Threading
    Module Module1
      Private val1 As Integer
      Private val2 As Integer

      Public Property ans() As Integer
        Get
          Return _ans
        End Get
        Private Set(ByVal value As Integer)
          _ans = value
        End Set
      End Property
      Private _ans As Integer

      Sub Main()
        val1 = 1
        val2 = 2
        ans = 0

        'スレッド生成
        Dim newThread As Thread = ThreadBuilder.NewThread(Of Integer)(AddressOf Method, AddressOf CallBack)

        'スレッド開始
        newThread.Start()

        'メインスレッドの処理

        'サブスレッドの完了待ち
        newThread.Join()
        Console.WriteLine(ans)
        Console.ReadLine()
      End Sub

      ''' <summary>
      ''' 別スレッドに実行させたい処理
      ''' </summary>
      Private Function Method() As Integer
        Return val1 + val2
      End Function

      ''' <summary>
      ''' スレッド完了後に戻り値をセットする処理
      ''' </summary>
      Friend Sub CallBack(ByVal returnValue As Integer)
        ans = returnValue
      End Sub
    End Module
引用返信 削除キー/
■33677 / inTopicNo.9)  Re[6]: Threading.Threadで戻り値を取得したい
□投稿者/ ゆう 一般人(4回)-(2017/09/01(Fri) 16:12:22)
  • アイコンありがとうございました

    期待どおりの結果が得られました
解決み!
引用返信 削除キー/



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

このトピックに書きこむ

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

Mode/  Pass/


- Child Tree -