トップ回答者
Socket通信 networkstreamを用いた際に接続クライアントを1個→2個に増やすとサーバー側の受信速度が遅くなる件

質問
-
環境:VisualStudio.net VB2010
業務用ソフトを開発中ですが表題の問題が発生しているためソケット通信にお詳しい方がいらっしゃいましたら何卒お知恵をお貸し願えませんでしょうか?
ネット上の情報をもとにTCPListenerクラスを用いた複数クライアントからの同時接続受け入れ可能なサーバーソフトを
開発しております。クライアントから10~60MB程度の画像データをByte型に変換して送信する仕様となっております。
その際、接続クライアントが1個の場合はほぼ理論値通りの転送速度(1000Mbpsに近いもの)が得られておりますが、
接続クライアントを2個に増やして両クライアントから連続して画像データを送信すると、どちらの画像データの受信速度も
クライアント1個送信時に4ms程度のものが400msに増えてしまいます。接続ポートを分ければよいのでは?と思い
クライアントごとに50000、50001 とポートを分けて接続しましたが結果は変わりませんでした。
クライアントが2個以上接続時にもデータの送信速度を落とさないようにするためにはどのような設定をすればよいのでしょうか?
参考までに下記にソース部を記載します。
①クライアント接続を待っている部分
'/** セカンドスレッドで実行されるサーバーのListen **"'サーバーのListenPrivate Sub ServerListen(aport As Integer)'TcpListenerを作成Listener = New TcpListener(IPAddress.Any, Integer.Parse(aport))Listener.Start()' クライアントの接続を受けるための永久ループTryDo' Listener.AcceptSocketは同期メソドで接続要求が有るまで '値を返さずここで待機します' 新しい接続要求ががあると接続を許可して' 新しいソケットを返しますDim socketForClient As Socket = Listener.AcceptSocket()'クライアント毎の接続とフォームのインスタンスを渡すDim handler As New ClientHandler(socketForClient, Me)'ListクラスにClientHandlerのインスタンスを保 持します Me.BeginInvoke(New dlgsetList(AddressOf Me.addNewClient), New Object() {handler})'読み込みを開始handler.StartRead()Loop While TrueEnd TryEnd Sub②接続された場合のコンストラクタ部
'クラスのコンストラクタPublic Sub New(ByVal socketForClient As Socket, ByVal _FomServer As FormMain)'呼び出し側のSocketを保持socket = socketForClient'呼び出し側のフォームのインスタンスを保持formMaineServer = _FomServer'読み込み用のバッファbuffer = New Byte(1024) {}'socketの読み書き用のstreamを作成しますnetworkStream = New NetworkStream(socketForClient)'読み込み完了時にCLRから呼ばれるメソドcallbackRead = New AsyncCallback(AddressOf Me.OnReadComplete)'書き込み完了時にCLRから呼ばれるメソドcallbackWrite = New AsyncCallback(AddressOf Me.OnWriteComplete)End Sub
③実際のデータ受信部
Public Sub StartRead()networkStream.BeginRead(buffer, 0, buffer.Length, callbackRead, Nothing) End Sub④データ受信
'networkStream.BeginReadの別スレッドから、読み込み完了時 '又はクライアント切断時にコールバックされます。Private Sub OnReadComplete(ByVal ar As IAsyncResult)Try'受信文字をStreamから読み込みますIf networkStream Is Nothing ThenExit SubEnd If'受信バイト数が返るDim bytesRead As Integer = networkStream.EndRead(ar)If bytesRead > 0 ThengetData(buffer, bytesRead)'次の受信を待つnetworkStream.BeginRead(buffer, 0, buffer.Length, callbackRead, Nothing) Else'終了ボタンが押され場合はここに落ちる'クライアントのList<T>からの削除formMaineServer.Invoke(New dlgsetList(AddressOf formMaineServer.deleteClient), New Object() {Me})networkStream.Close()socket.Close()networkStream = NothingThread.Sleep(20) 'これを入れないとNullReferenceException が起きる socket = NothingEnd IfCatch ex As Exception'エラーログの書き込みformMaineServer.Invoke(New dlgWriteLog(AddressOf formMaineServer.WriteLog), New Object() {"受信エラーが起こりました " & ex.ToString()})End TryEnd Subちなみに本サーバーアプリを2個起動させて2個クライアントソフトをそれぞれのサーバーアプリに接続すると
データ送信時間は遅くならないことも確認されておりますが、ソフトの使用上、どうしてもサーバーアプリを1個に
まとめる必要がございます。
専門家、有識者の方々のお知恵を拝借したく、どうぞよろしくお願いいたします。
回答
-
1Gbpsのイーサネットで効率100%であったとしても
1[Gbps] = 1000[Mbps] = 125[MByte/sec]
10MBを転送するのに必要な時間 10[MByte] / 125[MByte/sec] = 0.08[sec]
60MBを転送するのに必要な時間 60[MByte] / 125[MByte/sec] = 0.48[sec]となります。実効速度は100%にならないので、もっと時間がかかるはずです。
さらに、2クライアントが同時接続すれば1クライアントが占有できるのは半分になるので時間は倍になりますし、もっと増えればもっと時間がかかります。
つまり、4ミリ秒で転送ができているのがあり得ないです。時間の計測をどのように行っているか示されていないですが、そのあたりのやり方を見直してみては?
以下、提示されていない部分を推測して書きなおしてみる
Imports System.Net Imports System.Net.Sockets Public Class FormMain Private Listener As TcpListener Private address As TextBox Private lsb As ListBox Private log As TextBox Private clientCount As Integer Private totalStart As DateTime Sub New() InitializeComponent() Dim tip As New ToolTip address = New TextBox() With {.Left = 10, .Top = 10, .Width = 100, .Text = "127.0.0.1"} tip.SetToolTip(address, "サーバーアドレス") Me.Controls.Add(address) Dim port As New NumericUpDown() With {.Minimum = 1, .Maximum = 65535, .Value = 10000, .Left = 10, .Top = Me.address.Bottom + 5, .Width = 100} tip.SetToolTip(port, "サーバーポート") Me.Controls.Add(port) Dim btnStartServer As New Button With {.Text = "Server", .Left = 10, .Top = port.Bottom + 5} AddHandler btnStartServer.Click, _ Sub(s, e) ServerListen(CInt(port.Value)) CType(s, Button).Enabled = False End Sub Me.Controls.Add(btnStartServer) Dim count As New NumericUpDown() With {.Minimum = 1, .Maximum = 5, .Value = 2, .Left = 150, .Top = port.Top, .Width = 50} tip.SetToolTip(count, "同時接続数") Me.Controls.Add(count) Dim size As New NumericUpDown() With {.Minimum = 1, .Maximum = 100, .Value = 60, .Left = count.Right + 5, .Top = count.Top, .Width = 50} tip.SetToolTip(size, "転送サイズ(MB)") Me.Controls.Add(size) Dim btnClient As New Button() With {.Text = "Client", .Left = 150, .Top = btnStartServer.Top} AddHandler btnClient.Click, _ Sub(s, e) Dim serverAddress As IPAddress = Nothing Try serverAddress = IPAddress.Parse(address.Text) Catch ex As Exception MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error) Exit Sub End Try StartClient(serverAddress, CInt(port.Value), CInt(count.Value), CByte(size.Value)) End Sub Me.Controls.Add(btnClient) lsb = New ListBox() With {.Left = 0, .Top = btnStartServer.Bottom + 5, .Height = 50, .Width = Me.ClientSize.Width, .Anchor = CType(&HD, AnchorStyles), .IntegralHeight = False} Me.Controls.Add(lsb) log = New TextBox() With {.Left = 0, .Top = lsb.Bottom + 5, .Width = Me.ClientSize.Width, .Height = Me.ClientSize.Height - .Top, .Anchor = CType(&HF, AnchorStyles), .Multiline = True, .ScrollBars = ScrollBars.Both} Me.Controls.Add(log) End Sub Friend Sub addNewClient(ByVal ch As ClientHandler) lsb.Items.Add(ch) End Sub Friend Sub deleteClient(ByVal ch As ClientHandler) lsb.Items.Remove(ch) End Sub Friend Sub WriteLog(ByVal msg As String) If (Me.InvokeRequired) Then Me.BeginInvoke(Sub() WriteLog(msg)) Else System.Diagnostics.Debug.WriteLine(msg) log.AppendText(msg + vbCrLf) End If End Sub Private Sub ServerListen(portNumber As Integer) Dim thread As System.Threading.Thread thread = New System.Threading.Thread _ (Sub() Me.Listener = New TcpListener(IPAddress.Any, portNumber) Me.Listener.Start() Try Do Dim socketForClient As Socket = Listener.AcceptSocket() Dim handler As New ClientHandler(socketForClient) AddHandler handler.Closed, _ Sub(s, e) Me.BeginInvoke _ (Sub() Dim ela As TimeSpan = (handler.EndTime - handler.StartTime) Dim mbps As Double = handler.Length * 8 / ela.TotalSeconds / 1024 / 1024 WriteLog(String.Format("{0,5} > {1:HH:mm:ss.fff} - {2:HH:mm:ss.fff} # {3,5:0}ms # {4,8:f3}Mbps", handler.Port, handler.StartTime, handler.EndTime, ela.TotalMilliseconds, mbps)) deleteClient(handler) If (System.Threading.Interlocked.Decrement(Me.clientCount) = 0) Then WriteLog(String.Format("{0:0}ms", (handler.EndTime - Me.totalStart).TotalMilliseconds)) End If End Sub) End Sub Me.BeginInvoke(Sub() addNewClient(handler) End Sub) handler.StartRead() Loop While True Catch ex As Exception Me.BeginInvoke(Sub() MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)) End Try End Sub) thread.IsBackground = True thread.Start() End Sub Private Sub StartClient(ByVal address As IPAddress, ByVal portNumber As Integer, ByVal count As Integer, ByVal megabyte As Byte) Me.log.Clear() Me.clientCount = 0 Dim ep As New IPEndPoint(address, portNumber) Dim data() As Byte data = New Byte(1024 * 1024 * megabyte) {} Dim rnd As New Random rnd.NextBytes(data) For i As Integer = 1 To count Dim thread As New System.Threading.Thread _ (Sub() Dim start As DateTime = DateTime.Now If (System.Threading.Interlocked.Increment(Me.clientCount) = 1) Then Me.totalStart = start End If Dim client As New TcpClient() Try client.Connect(ep) Catch ex As Exception MessageBox.Show(ex.Message) Exit Sub End Try WriteLog(String.Format("{0,5} < {1:HH:mm:ss.fff}", CType(client.Client.LocalEndPoint, IPEndPoint).Port, start)) Dim stream = client.GetStream() stream.Write(data, 0, data.Length) stream.Close() End Sub) thread.IsBackground = True thread.Start() Next End Sub End Class Public Class ExceptionEventArgs Inherits EventArgs Public Message As String Public Exception As Exception End Class Friend Class ClientHandler Public Socket As Socket Private BUffer() As Byte Private NetworkStream As NetworkStream Private callbackRead As AsyncCallback Private callbackWrite As AsyncCallback Public Port As Integer Public Event ReadError As EventHandler(Of ExceptionEventArgs) Public Event Closed As EventHandler(Of EventArgs) Public Property StartTime As DateTime Public Property EndTime As DateTime Public Sub New(ByVal socketForClient As Socket) StartTime = DateTime.Now EndTime = DateTime.MaxValue Socket = socketForClient BUffer = New Byte(1024) {} NetworkStream = New NetworkStream(socketForClient) callbackRead = New AsyncCallback(AddressOf Me.OnReadComplete) callbackWrite = New AsyncCallback(AddressOf Me.OnWriteComplete) Port = CType(socketForClient.RemoteEndPoint, IPEndPoint).Port End Sub Public Sub StartRead() NetworkStream.BeginRead(BUffer, 0, BUffer.Length, callbackRead, Nothing) End Sub Private Sub OnReadComplete(ByVal ar As IAsyncResult) Try If NetworkStream Is Nothing Then Exit Sub End If Dim bytesRead As Integer = NetworkStream.EndRead(ar) If bytesRead > 0 Then getData(BUffer, bytesRead) NetworkStream.BeginRead(BUffer, 0, BUffer.Length, callbackRead, Nothing) Else NetworkStream.Close() Socket.Close() Socket.Dispose() NetworkStream = Nothing 'System.Threading.Thread.Sleep(20) 'これを入れないとNullReferenceExceptionが起きる Socket = Nothing EndTime = DateTime.Now RaiseEvent Closed(Me, EventArgs.Empty) End If Catch ex As Exception RaiseEvent ReadError(Me, New ExceptionEventArgs() With {.Exception = ex, .Message = "受信エラーが起こりました"}) End Try End Sub Public Property Length As Long Private Sub getData(ByRef buffer As Byte(), ByVal count As Integer) Length = Length + count End Sub Private Sub OnWriteComplete(ByVal ar As IAsyncResult) End Sub End Class
#テスト環境では1クライアントだと800Mbps位、2クライアントで900Mbps位
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 編集済み gekkaMVP 2017年7月8日 9:44
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年7月10日 1:02
- 回答としてマーク 立花楓Microsoft employee, Moderator 2017年9月5日 6:21
すべての返信
-
1Gbpsのイーサネットで効率100%であったとしても
1[Gbps] = 1000[Mbps] = 125[MByte/sec]
10MBを転送するのに必要な時間 10[MByte] / 125[MByte/sec] = 0.08[sec]
60MBを転送するのに必要な時間 60[MByte] / 125[MByte/sec] = 0.48[sec]となります。実効速度は100%にならないので、もっと時間がかかるはずです。
さらに、2クライアントが同時接続すれば1クライアントが占有できるのは半分になるので時間は倍になりますし、もっと増えればもっと時間がかかります。
つまり、4ミリ秒で転送ができているのがあり得ないです。時間の計測をどのように行っているか示されていないですが、そのあたりのやり方を見直してみては?
以下、提示されていない部分を推測して書きなおしてみる
Imports System.Net Imports System.Net.Sockets Public Class FormMain Private Listener As TcpListener Private address As TextBox Private lsb As ListBox Private log As TextBox Private clientCount As Integer Private totalStart As DateTime Sub New() InitializeComponent() Dim tip As New ToolTip address = New TextBox() With {.Left = 10, .Top = 10, .Width = 100, .Text = "127.0.0.1"} tip.SetToolTip(address, "サーバーアドレス") Me.Controls.Add(address) Dim port As New NumericUpDown() With {.Minimum = 1, .Maximum = 65535, .Value = 10000, .Left = 10, .Top = Me.address.Bottom + 5, .Width = 100} tip.SetToolTip(port, "サーバーポート") Me.Controls.Add(port) Dim btnStartServer As New Button With {.Text = "Server", .Left = 10, .Top = port.Bottom + 5} AddHandler btnStartServer.Click, _ Sub(s, e) ServerListen(CInt(port.Value)) CType(s, Button).Enabled = False End Sub Me.Controls.Add(btnStartServer) Dim count As New NumericUpDown() With {.Minimum = 1, .Maximum = 5, .Value = 2, .Left = 150, .Top = port.Top, .Width = 50} tip.SetToolTip(count, "同時接続数") Me.Controls.Add(count) Dim size As New NumericUpDown() With {.Minimum = 1, .Maximum = 100, .Value = 60, .Left = count.Right + 5, .Top = count.Top, .Width = 50} tip.SetToolTip(size, "転送サイズ(MB)") Me.Controls.Add(size) Dim btnClient As New Button() With {.Text = "Client", .Left = 150, .Top = btnStartServer.Top} AddHandler btnClient.Click, _ Sub(s, e) Dim serverAddress As IPAddress = Nothing Try serverAddress = IPAddress.Parse(address.Text) Catch ex As Exception MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error) Exit Sub End Try StartClient(serverAddress, CInt(port.Value), CInt(count.Value), CByte(size.Value)) End Sub Me.Controls.Add(btnClient) lsb = New ListBox() With {.Left = 0, .Top = btnStartServer.Bottom + 5, .Height = 50, .Width = Me.ClientSize.Width, .Anchor = CType(&HD, AnchorStyles), .IntegralHeight = False} Me.Controls.Add(lsb) log = New TextBox() With {.Left = 0, .Top = lsb.Bottom + 5, .Width = Me.ClientSize.Width, .Height = Me.ClientSize.Height - .Top, .Anchor = CType(&HF, AnchorStyles), .Multiline = True, .ScrollBars = ScrollBars.Both} Me.Controls.Add(log) End Sub Friend Sub addNewClient(ByVal ch As ClientHandler) lsb.Items.Add(ch) End Sub Friend Sub deleteClient(ByVal ch As ClientHandler) lsb.Items.Remove(ch) End Sub Friend Sub WriteLog(ByVal msg As String) If (Me.InvokeRequired) Then Me.BeginInvoke(Sub() WriteLog(msg)) Else System.Diagnostics.Debug.WriteLine(msg) log.AppendText(msg + vbCrLf) End If End Sub Private Sub ServerListen(portNumber As Integer) Dim thread As System.Threading.Thread thread = New System.Threading.Thread _ (Sub() Me.Listener = New TcpListener(IPAddress.Any, portNumber) Me.Listener.Start() Try Do Dim socketForClient As Socket = Listener.AcceptSocket() Dim handler As New ClientHandler(socketForClient) AddHandler handler.Closed, _ Sub(s, e) Me.BeginInvoke _ (Sub() Dim ela As TimeSpan = (handler.EndTime - handler.StartTime) Dim mbps As Double = handler.Length * 8 / ela.TotalSeconds / 1024 / 1024 WriteLog(String.Format("{0,5} > {1:HH:mm:ss.fff} - {2:HH:mm:ss.fff} # {3,5:0}ms # {4,8:f3}Mbps", handler.Port, handler.StartTime, handler.EndTime, ela.TotalMilliseconds, mbps)) deleteClient(handler) If (System.Threading.Interlocked.Decrement(Me.clientCount) = 0) Then WriteLog(String.Format("{0:0}ms", (handler.EndTime - Me.totalStart).TotalMilliseconds)) End If End Sub) End Sub Me.BeginInvoke(Sub() addNewClient(handler) End Sub) handler.StartRead() Loop While True Catch ex As Exception Me.BeginInvoke(Sub() MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)) End Try End Sub) thread.IsBackground = True thread.Start() End Sub Private Sub StartClient(ByVal address As IPAddress, ByVal portNumber As Integer, ByVal count As Integer, ByVal megabyte As Byte) Me.log.Clear() Me.clientCount = 0 Dim ep As New IPEndPoint(address, portNumber) Dim data() As Byte data = New Byte(1024 * 1024 * megabyte) {} Dim rnd As New Random rnd.NextBytes(data) For i As Integer = 1 To count Dim thread As New System.Threading.Thread _ (Sub() Dim start As DateTime = DateTime.Now If (System.Threading.Interlocked.Increment(Me.clientCount) = 1) Then Me.totalStart = start End If Dim client As New TcpClient() Try client.Connect(ep) Catch ex As Exception MessageBox.Show(ex.Message) Exit Sub End Try WriteLog(String.Format("{0,5} < {1:HH:mm:ss.fff}", CType(client.Client.LocalEndPoint, IPEndPoint).Port, start)) Dim stream = client.GetStream() stream.Write(data, 0, data.Length) stream.Close() End Sub) thread.IsBackground = True thread.Start() Next End Sub End Class Public Class ExceptionEventArgs Inherits EventArgs Public Message As String Public Exception As Exception End Class Friend Class ClientHandler Public Socket As Socket Private BUffer() As Byte Private NetworkStream As NetworkStream Private callbackRead As AsyncCallback Private callbackWrite As AsyncCallback Public Port As Integer Public Event ReadError As EventHandler(Of ExceptionEventArgs) Public Event Closed As EventHandler(Of EventArgs) Public Property StartTime As DateTime Public Property EndTime As DateTime Public Sub New(ByVal socketForClient As Socket) StartTime = DateTime.Now EndTime = DateTime.MaxValue Socket = socketForClient BUffer = New Byte(1024) {} NetworkStream = New NetworkStream(socketForClient) callbackRead = New AsyncCallback(AddressOf Me.OnReadComplete) callbackWrite = New AsyncCallback(AddressOf Me.OnWriteComplete) Port = CType(socketForClient.RemoteEndPoint, IPEndPoint).Port End Sub Public Sub StartRead() NetworkStream.BeginRead(BUffer, 0, BUffer.Length, callbackRead, Nothing) End Sub Private Sub OnReadComplete(ByVal ar As IAsyncResult) Try If NetworkStream Is Nothing Then Exit Sub End If Dim bytesRead As Integer = NetworkStream.EndRead(ar) If bytesRead > 0 Then getData(BUffer, bytesRead) NetworkStream.BeginRead(BUffer, 0, BUffer.Length, callbackRead, Nothing) Else NetworkStream.Close() Socket.Close() Socket.Dispose() NetworkStream = Nothing 'System.Threading.Thread.Sleep(20) 'これを入れないとNullReferenceExceptionが起きる Socket = Nothing EndTime = DateTime.Now RaiseEvent Closed(Me, EventArgs.Empty) End If Catch ex As Exception RaiseEvent ReadError(Me, New ExceptionEventArgs() With {.Exception = ex, .Message = "受信エラーが起こりました"}) End Try End Sub Public Property Length As Long Private Sub getData(ByRef buffer As Byte(), ByVal count As Integer) Length = Length + count End Sub Private Sub OnWriteComplete(ByVal ar As IAsyncResult) End Sub End Class
#テスト環境では1クライアントだと800Mbps位、2クライアントで900Mbps位
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 編集済み gekkaMVP 2017年7月8日 9:44
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年7月10日 1:02
- 回答としてマーク 立花楓Microsoft employee, Moderator 2017年9月5日 6:21
-
bufferのサイズがちょっと小さいかな、という感じもします(ふつうのEthenerのパケットは1400バイトくらいあるので。1MByteとっても大丈夫ではないでしょうか)。
おおむね、提示されているコードにそれほど問題はないと思います。
ただ、提示されていない、具体的にはgetDataの実装で、たとえばロックを獲得しているとか、メインウインドウへBeginInvokeしているとか、詰まる原因があるのでは、と思います。- 編集済み jzkey 2017年7月8日 10:31 中途送信なので修正
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年7月12日 0:13
-
Thread.Sleep(20) 'これを入れないとNullReferenceExceptionが起きる
苦労されている形跡が見えます。環境をVisual Studio 2012以降かつ.NET Framework 4.5以降にアップデートされますと、Async および Await を使用した非同期プログラミングを利用できます。AsyncCallbackの苦労が嘘のように解消され、パフォーマンスが向上しますので、こちらを推奨します。
# ちなみに.NET 4.0~4.5.1はサポート終了済みです。.NET 2.0 SP1にてソケット パフォーマンスの強化が行われていますが、今回の質問ではこちらを使用しなくても十分なパフォーマンスを得られる領域の問題と思われますので、紹介までにとどめます。
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年7月12日 0:13
-
jzkey様
>getDataの実装で、たとえばロックを獲得しているとか、メインウインドウへBeginInvokeしているとか、詰まる原因があるのでは、と思います。
→ご指摘通り、getDataの中でBeginInvokeを実行していました。その関数が実行されている時間中に他のスレッドからのアクセスを拒否しているためにその分の待ち時間が発生しておりました。ですのでBeginInvokeをやめて通常の関数の形での呼び出しにすればうまくいくのですが、BeginInvoke内のUI要素へのアクセス時にエラーが発生してしまうようになりました。ロックされる時間を最小限にするためにUI要素にアクセスする関数部位(エラーが発生する箇所)だけにSyncLock?処理を入れましたがうまくいかないようで相変わらずエラーが発生しており作業が中断しております。UI要素へアクセスする方法はDLLで提供されている機能のためその使用を避けることはできない状態です。やはりSynclockを理解して使用するしかないのでしょうか?参考までにサンプルソースを添付いたします。Friend Shared Function AccessData(ByVal a As toto.TT)
Try
'SyncLock (a) '→入れてみましたが効果なしDim bbb As toto.Ibbb
bbb = a.getImage(index)'→ここでエラーが発生
'End SyncLock '→入れてみましたが効果なしCatch ex As Exception
Console.WriteLine(ex.Message)
Throw
End Try
end Function