Threads Vs. Handles

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I was working on a Multi-Threaded app and I noticed something.

If i make an app that only uses timers, [(begin/end) send, recv, accept {tcp
stuff}] it looks like that application is a mutil-threaded app. BUT. the
only thing that goes up is the handles.

Yes yes I know, I didnt call the (new Threading.thread) object but, is it
Needed?

Moreover, Most of the multi-threaded tcp/ip apps that i have seen only sit
in a do...loop statement waiting to be shut down.

What is the correct way to create a multi-threaded tcp server?
 
I'm not an expert in this area but here are my thoughts.

If you are writing a server then you want to create a thread for each client
that connects. This way each has their own "state". If you are using
timers then you are all running in the same thread and a blocking on one
timer will block all timers. In threading you won't run into one connection
to the server blocking all the other connections.

I'm not sure what you mean when you say "sit in a do...loop statement" The
main thread should be just waiting to fire off working thread when a client
connects. When the connection is finished the worker thread should die.

I hope I've helped.
Chris
 
Yea a reply :)

Here is the code from the lister class.
Private Sub Listen_Callback(ByVal ar As IAsyncResult)
Dim t As New Client(_lSocket.EndAccept(ar))
t.Connect()
_lSocket.BeginAccept(New AsyncCallback(AddressOf Listen_Callback),
_lSocket)

End Sub



Here is the code for the client..
i only implement so i can get the dispose.

Based on "_Do_Connect()" is the class threaded?.. also do I really need
threading? I mean I did this class without the threading. and had around
2,399 connections and the respons was good. Note: the raiseevents are not
in, but the one that did the 2399 connections was sending around 1k of junk
data.

Public Class Client
implements iClient
Private _Socket As Net.Sockets.Socket
Private _RecvBuffer(1024) As Byte
Private _SendBuffer(1024) As Byte
Private _ID As String = Guid.NewGuid.ToString
Private _recvMsg As String
Private _Timer As Threading.Timer
Private _MyThread As Threading.Thread
Private _ShutDown As Boolean
Public Event Disconnected(ByVal ID As String) Implements
iClient.Disconnected
Public Event Connected(ByVal ID As String) Implements iClient.Connected
Public Event Data(ByVal ID As String, ByVal Data As String) Implements
iClient.Data

Public Property Socket() As System.Net.Sockets.Socket Implements
iClient.Socket
Get
Return _Socket
End Get
Set(ByVal Value As System.Net.Sockets.Socket)
_Socket = Value
End Set
End Property

'
Public Property ID() As String Implements iClient.ID
Get
Return _ID
End Get
Set(ByVal Value As String)
End Set
End Property

'
Private Sub _Do_recv(ByVal ar As System.IAsyncResult)
Try
Dim read As Integer = _Socket.EndReceive(ar)
_recvMsg = System.Text.Encoding.ASCII.GetString(_RecvBuffer, 0,
read)
_Socket.BeginReceive(_RecvBuffer, 0, 1024, 0, New
AsyncCallback(AddressOf _Do_recv), _Socket)
Catch ex As Exception
Me.Disconnect()
End Try
End Sub
'
Private Sub _Do_Send(ByVal ar As System.IAsyncResult)
Try
Dim tmpSend As Int16 = _Socket.EndSend(ar)
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

Private Sub _Do_CheckUp(ByVal state As Object)
Try
Dim tmpSendBytes() As Byte = {0}
_Socket.Send(tmpSendBytes)
If _Socket.Poll(1000, Net.Sockets.SelectMode.SelectWrite) =
False Then
Me.Disconnect()
End If
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

Private Sub _Do_Connect()
Try

_Socket.Blocking = False
_Socket.BeginReceive(_RecvBuffer, 0, 1024, 0, New
AsyncCallback(AddressOf _Do_recv), _Socket)
_Timer = New Threading.Timer(New
Threading.TimerCallback(AddressOf _Do_CheckUp), Nothing, 5000, 5000)
Me.Send("Hello!")
Do While _ShutDown = False
_MyThread.Sleep(100)
Loop
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

'
Public Sub Connect() Implements iClient.Connect
Try
_MyThread = New Threading.Thread(AddressOf _Do_Connect)
_MyThread.Start()
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

Public Sub Disconnect() Implements iClient.Disconnect
Me.Dispose()
End Sub
'
Public Sub Send(ByVal Data As String) Implements iClient.Send
Try
Dim tmpData() As Byte = System.Text.Encoding.ASCII.GetBytes(Data)
_Socket.BeginSend(tmpData, 0, tmpData.Length, 0, New
AsyncCallback(AddressOf _Do_Send), _Socket)

Catch ex As Exception
Me.Disconnect()
End Try
End Sub
'
Public Sub Dispose() Implements System.IDisposable.Dispose
Try
_Timer.Dispose()
_ShutDown = True
_MyThread.Abort()
_Socket.Shutdown(Net.Sockets.SocketShutdown.Both)
_Socket.Close()
CloseHandle(_Socket.Handle)
_Socket = Nothing
' GC.SuppressFinalize(Me)
Catch ex As Exception
End Try

End Sub

Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
' Use interop to call the method necessary
' to clean up the unmanaged resource.
<System.Runtime.InteropServices.DllImport("Kernel32")> _
Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
End Function

Public Sub New(ByVal Sock As Net.Sockets.Socket)
_Socket = Sock
End Sub
End Class
 
Where you able to view the project I posted for your review?

--
William Stacey, MVP
http://mvp.support.microsoft.com

Jason at PTE said:
Yea a reply :)

Here is the code from the lister class.
Private Sub Listen_Callback(ByVal ar As IAsyncResult)
Dim t As New Client(_lSocket.EndAccept(ar))
t.Connect()
_lSocket.BeginAccept(New AsyncCallback(AddressOf Listen_Callback),
_lSocket)

End Sub



Here is the code for the client..
i only implement so i can get the dispose.

Based on "_Do_Connect()" is the class threaded?.. also do I really need
threading? I mean I did this class without the threading. and had around
2,399 connections and the respons was good. Note: the raiseevents are not
in, but the one that did the 2399 connections was sending around 1k of junk
data.

Public Class Client
implements iClient
Private _Socket As Net.Sockets.Socket
Private _RecvBuffer(1024) As Byte
Private _SendBuffer(1024) As Byte
Private _ID As String = Guid.NewGuid.ToString
Private _recvMsg As String
Private _Timer As Threading.Timer
Private _MyThread As Threading.Thread
Private _ShutDown As Boolean
Public Event Disconnected(ByVal ID As String) Implements
iClient.Disconnected
Public Event Connected(ByVal ID As String) Implements iClient.Connected
Public Event Data(ByVal ID As String, ByVal Data As String) Implements
iClient.Data

Public Property Socket() As System.Net.Sockets.Socket Implements
iClient.Socket
Get
Return _Socket
End Get
Set(ByVal Value As System.Net.Sockets.Socket)
_Socket = Value
End Set
End Property

'
Public Property ID() As String Implements iClient.ID
Get
Return _ID
End Get
Set(ByVal Value As String)
End Set
End Property

'
Private Sub _Do_recv(ByVal ar As System.IAsyncResult)
Try
Dim read As Integer = _Socket.EndReceive(ar)
_recvMsg = System.Text.Encoding.ASCII.GetString(_RecvBuffer, 0,
read)
_Socket.BeginReceive(_RecvBuffer, 0, 1024, 0, New
AsyncCallback(AddressOf _Do_recv), _Socket)
Catch ex As Exception
Me.Disconnect()
End Try
End Sub
'
Private Sub _Do_Send(ByVal ar As System.IAsyncResult)
Try
Dim tmpSend As Int16 = _Socket.EndSend(ar)
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

Private Sub _Do_CheckUp(ByVal state As Object)
Try
Dim tmpSendBytes() As Byte = {0}
_Socket.Send(tmpSendBytes)
If _Socket.Poll(1000, Net.Sockets.SelectMode.SelectWrite) =
False Then
Me.Disconnect()
End If
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

Private Sub _Do_Connect()
Try

_Socket.Blocking = False
_Socket.BeginReceive(_RecvBuffer, 0, 1024, 0, New
AsyncCallback(AddressOf _Do_recv), _Socket)
_Timer = New Threading.Timer(New
Threading.TimerCallback(AddressOf _Do_CheckUp), Nothing, 5000, 5000)
Me.Send("Hello!")
Do While _ShutDown = False
_MyThread.Sleep(100)
Loop
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

'
Public Sub Connect() Implements iClient.Connect
Try
_MyThread = New Threading.Thread(AddressOf _Do_Connect)
_MyThread.Start()
Catch ex As Exception
Me.Disconnect()
End Try
End Sub

Public Sub Disconnect() Implements iClient.Disconnect
Me.Dispose()
End Sub
'
Public Sub Send(ByVal Data As String) Implements iClient.Send
Try
Dim tmpData() As Byte = System.Text.Encoding.ASCII.GetBytes(Data)
_Socket.BeginSend(tmpData, 0, tmpData.Length, 0, New
AsyncCallback(AddressOf _Do_Send), _Socket)

Catch ex As Exception
Me.Disconnect()
End Try
End Sub
'
Public Sub Dispose() Implements System.IDisposable.Dispose
Try
_Timer.Dispose()
_ShutDown = True
_MyThread.Abort()
_Socket.Shutdown(Net.Sockets.SocketShutdown.Both)
_Socket.Close()
CloseHandle(_Socket.Handle)
_Socket = Nothing
' GC.SuppressFinalize(Me)
Catch ex As Exception
End Try

End Sub

Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
' Use interop to call the method necessary
' to clean up the unmanaged resource.
<System.Runtime.InteropServices.DllImport("Kernel32")> _
Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
End Function

Public Sub New(ByVal Sock As Net.Sockets.Socket)
_Socket = Sock
End Sub
End Class
 
The web ngs probably don't show posts with attachments. It is a zip'd
solution with two projects (client and server). Send me an email and I will
reply with the attachment. I don't really want to cut and paste all the
code here again. Cheers!

--
William Stacey, MVP
http://mvp.support.microsoft.com

Jason at PTE said:
Can you please report it :)
 
Chris said:
I'm not an expert in this area but here are my thoughts.

If you are writing a server then you want to create a thread for each
client that connects. This way each has their own "state". If you are
using timers then you are all running in the same thread and a blocking on
one timer will block all timers. In threading you won't run into one
connection to the server blocking all the other connections.

Actually, you certanily don't want to do a 1 to 1 client to thread mapping.
Threads cost a fair amount and in any moderatly busy server you will end up
with an overwhelming amount of threads. Imagine a server that deals with 200
clients at any given time, assuming build up and tear down time, how many
threads might you have going? What about having a couple hundred thread's
being torn down at any given moment?

To expensive, and it will probably cause considerable contention as the
servers traffic goes up further..

A much better method is using the async methods provided with the various
networking classes(TcpClient adds some in 2.0, I think, but Socket has async
methods in 1.0). These methods execute using a thread pool which has less
overhead.
 
Actually, you certanily don't want to do a 1 to 1 client to thread
mapping.
Threads cost a fair amount and in any moderatly busy server you will end up
with an overwhelming amount of threads. Imagine a server that deals with 200
clients at any given time, assuming build up and tear down time, how many
threads might you have going? What about having a couple hundred thread's
being torn down at any given moment?

Actually I used to think that also. But Chad from Indy .Net changed my mind
a bit:
http://www.dotnet247.com/247referen....swissdelphicenter.ch/en/showarticle.php?id=4

Blocking is not bad and threads are not bad. Most of the time server
threads spend is blocking waiting on IO, so context switching is not so much
an issue. The thread creation and tear down can be buffered with your own
thread pool. 200 threads should not be an issue. A busy IIS server does
more. 1000 current is about the max. I would not go that high. So you
could say have 500 workers active and queue the rest or return busy. There
is a lot more to factor in when looking at async -vs- client threads. async
is not thread free. You have the IOCP thread pool (1000 thread max IIRC)
that uses threads to service those sockets *and you have the .net thread
pool that handles the callbacks. Still have thread startup and teardown
issues and context switches. Threaded servers are a lot easier to create
and to verify their correctness. With a simple request/reply server (like a
web server), your own thread pool handling client requests starts looking
really good. A lot of weird things can catch you with async servers such
the order of completed operations not coming in order you expect, etc. Not
saying async in not the way to go, just saying threaded servers are better
then many folks would have you believe, a lot easier to create and maintain,
and work great. Note that most *nix servers still use blocking sockets and
fork a process (not a thread) to handle each client requests.
 
William Stacey said:
Actually I used to think that also. But Chad from Indy .Net changed my
mind
a bit:
http://www.dotnet247.com/247referen....swissdelphicenter.ch/en/showarticle.php?id=4

Which is yet another problem with Indy. I've found I cannot use it in good
faith...I just don't really like its design at all.
Blocking is not bad and threads are not bad. Most of the time server
threads spend is blocking waiting on IO, so context switching is not so
much
an issue. The thread creation and tear down can be buffered with your own
thread pool. 200 threads should not be an issue. A busy IIS server does
more. 1000 current is about the max. I would not go that high. So you
could say have 500 workers active and queue the rest or return busy.
There
is a lot more to factor in when looking at async -vs- client threads.
async
is not thread free. You have the IOCP thread pool (1000 thread max IIRC)
that uses threads to service those sockets *and you have the .net thread
pool that handles the callbacks. Still have thread startup and teardown
issues and context switches. Threaded servers are a lot easier to create
and to verify their correctness. With a simple request/reply server (like
a
web server), your own thread pool handling client requests starts looking
really good. A lot of weird things can catch you with async servers such
the order of completed operations not coming in order you expect, etc.
Not
saying async in not the way to go, just saying threaded servers are better
then many folks would have you believe, a lot easier to create and
maintain,
and work great. Note that most *nix servers still use blocking sockets
and
fork a process (not a thread) to handle each client requests.

Threading has alot of benefits, I'll agree. However, I think its foolish to
design your server using one thread per client simply because its easier. I
could, likewise, design my code to take 4 seconds to process a byte because
its easier than getting a megabyte done in that period of time, but you
would laugh me out of the room for thatt. Ease and simplicity is not an
excuse for being lazy, IMHO. The only thing Indy shows here is that they
feel that server developers are not interested in writing something
effeciently. It will work, but I do not really feel that there is a need for
several thousand threads, really, especially if your server is not running
as the only process on the machine.

A thread pool is a different matter. Whether you use ThreadPool or build
your own pool is one thing, but creating an entirely new thread, as was
suggested, is quite another. Somthing about creating 12,000(200 threads per
minute, 60 minutes per hour) threads an hour is unnerving.
 
Daniel O'Connell said:
Threading has alot of benefits, I'll agree. However, I think its foolish to
design your server using one thread per client simply because its easier. I
could, likewise, design my code to take 4 seconds to process a byte because
its easier than getting a megabyte done in that period of time, but you
would laugh me out of the room for thatt. Ease and simplicity is not an
excuse for being lazy, IMHO.

I think it really depends on the requirements. Ease and simplicity is a
justifiable excuse to be as lazy as you can get away with, IMO. I've
written lots of code which isn't as efficient as it might be (arguably
virtually all .NET code falls into this category) simply because it
gets the job done.

Using one thread per client is fine if you absolutely know you're not
going to get hundreds of concurrent requests - which may well happen if
you're writing an internal company app and the company doesn't have
that many employees :)
 
Threading has alot of benefits, I'll agree. However, I think its foolish
to
design your server using one thread per client simply because its easier. I
could, likewise, design my code to take 4 seconds to process a byte
because

Agreed. Easier is just one plus. Correctness is another. It is much
harder to get async correct. It may look like it works, and compile and
even run (for a while). But you can get very weird bugs when ordering
issues come once every 100000 operations or something. You can have issues
like that in either model, true, but eliminating a lot of complication gets
you closer out the gate especially after adding other complex locking issues
to the mixture.
A thread pool is a different matter. Whether you use ThreadPool or build
your own pool is one thing, but creating an entirely new thread, as was
suggested, is quite another. Somthing about creating 12,000(200 threads per
minute, 60 minutes per hour) threads an hour is unnerving.

True, and I agree about being "unnerving". However, let's not forget that
is happing anyway with async behind the covers. You just don't do it
explicitly, as it is done for you. Naturally, the thread pool and IOCP
thread pool "buffers" thread creation and reuses them, but it still happens
and your app still pays the tax - especially with spuratic connections
ramping up and down. Because of these and other issues, finding a clear
winner becomes blurry (at least for me). So when confronted with no clear
winner and one choice that is much easier to reason about and get right and
one this is not - I would tend to pick the easier one just from maintaince
and piece of mind standpoint even if I had to pay a small perf tax (which I
can't say is real because the matrix to figure that out is beyond me and
subject to variable usage patterns, etc.)

Potentially you could get the best of both worlds with your own ~"async"
thread pool of socket reader/writer threads that read requests and places
them into server queue. Server thread just processes the work items and
places replies into the r/w socket pool queue. The server queue could even
be a priority queue and server can post back into its' own queue for certain
kinds of recursive work. This also gives clear seperation between network
layer and the business logic layer of handling requests/replies. There is
just something I really like about that design, but need to bang that around
a bit more. Thanks Daniel. Cheers!
 
Jon Skeet said:
I think it really depends on the requirements. Ease and simplicity is a
justifiable excuse to be as lazy as you can get away with, IMO. I've
written lots of code which isn't as efficient as it might be (arguably
virtually all .NET code falls into this category) simply because it
gets the job done.

Yes, you can get away with it, but I think Indy shouldn't have taken that
approach. It wants to position itself as a premier library but forces
something that will not work with heavy usage based on the assumption that
ease trumps efficency.

As general purpose advice, I think its risky to give out.

But I did certainly speak a little to broadly, ;).
 
William Stacey said:
because

Agreed. Easier is just one plus. Correctness is another. It is much
harder to get async correct. It may look like it works, and compile and
even run (for a while). But you can get very weird bugs when ordering
issues come once every 100000 operations or something. You can have
issues
like that in either model, true, but eliminating a lot of complication
gets
you closer out the gate especially after adding other complex locking
issues
to the mixture.

Its tougher, no doubt, but no too bad. Atleast in C#, ;).

Now in C, thats fun.
True, and I agree about being "unnerving". However, let's not forget that
is happing anyway with async behind the covers. You just don't do it
explicitly, as it is done for you. Naturally, the thread pool and IOCP
thread pool "buffers" thread creation and reuses them, but it still
happens
and your app still pays the tax - especially with spuratic connections
ramping up and down. Because of these and other issues, finding a clear
winner becomes blurry (at least for me). So when confronted with no clear
winner and one choice that is much easier to reason about and get right
and
one this is not - I would tend to pick the easier one just from maintaince
and piece of mind standpoint even if I had to pay a small perf tax (which
I
can't say is real because the matrix to figure that out is beyond me and
subject to variable usage patterns, etc.)

Yes, async is still going to cost something, but its not going to cost
anywhere near as much as one-thread, one-client. You'll end up with fewer
threads and considerably fewer context switches, at the cost of a more
complicated design.
Potentially you could get the best of both worlds with your own ~"async"
thread pool of socket reader/writer threads that read requests and places
them into server queue. Server thread just processes the work items and
places replies into the r/w socket pool queue. The server queue could
even
be a priority queue and server can post back into its' own queue for
certain
kinds of recursive work. This also gives clear seperation between network
layer and the business logic layer of handling requests/replies. There is
just something I really like about that design, but need to bang that
around
a bit more. Thanks Daniel. Cheers!

It certainly would be interesting.
 
Back
Top