thread frozen

D

droopytoon

Hi,

I start a new thread (previous one was "thread timing") because I have
isolated my problem.
It has nothing to do with calling unmanaged C++ code (I removed it in a
test application).
I have a thread "_itTaskThread" running.
The application is listening on a TCP port.
It accepts 2 connection from a client.
I simulate a crash on the client side (using "Debug->StopDebugging").
I got a "Sockets.SocketException" (as expected) but it seems to freeze
my "_itTaskThread" thread for more than 3 seconds !
Why does this thread is frozen, it has nothing to do with Tcp socket
handling !
See code + logs here below :

Thanks in advance for your help,

Droopy.


Application (WinForms with a "OK" push button)

Form1.cs
--------

....
private ManualResetEvent _itTaskEvent = new ManualResetEvent (false);
private TimeSpan _maxItTaskElapsedTime = TimeSpan.MinValue;
private TimeSpan _minItTaskElapsedTime = TimeSpan.MaxValue;
private Tcp _tcp;
private System.Windows.Forms.Button buttonOK;
private Thread _itTaskThread = null;
....
public Form1()
{
InitializeComponent();

_tcp = new Tcp ();
_tcp.OnCommandReceived += new Tcp.CommandReceivedHandler
(CommandReceivedHandler);

_itTaskThread = new Thread (new ThreadStart (ItTaskProc));
_itTaskThread.Name = "ItTask thread";
_itTaskThread.Priority = ThreadPriority.Highest;
_itTaskThread.Start ();
}
....
public void ItTaskProc ()
{
Util.TraceLine ("ItTaskProc thread started");

DateTime dtCurrent = DateTime.Now;
DateTime dtLast = DateTime.MinValue;

try
{
while (true)
{
Util.TraceLine ("before WaitOne");
if (_itTaskEvent.WaitOne (25, false))
{
Util.TraceLine ("ItTaskProc end asked");
break;
}
Util.TraceLine ("after WaitOne");
Util.TraceLine ("before ItTaskProc");
Util.TraceLine ("_serialChannel.ItTask ()");
Util.TraceLine ("after ItTaskProc");
dtLast = dtCurrent;
dtCurrent = DateTime.Now;
Util.TraceLine ("dtCurrent=" + dtCurrent.ToString ("HH:mm:ss:fff:
") +
", dtLast=" + dtLast.ToString ("HH:mm:ss:fff: "));
TimeSpan diff = dtCurrent.Subtract (dtLast);
if (_minItTaskElapsedTime > diff)
{
_minItTaskElapsedTime = diff;
Util.TraceLine ("New mininimum ItTaskElapsedTime = " +
_minItTaskElapsedTime);
}
if (_maxItTaskElapsedTime < diff)
{
_maxItTaskElapsedTime = diff;
Util.TraceLine ("New maximum ItTaskElapsedTime = " +
_maxItTaskElapsedTime);
}
}
}
catch(ThreadAbortException abortException)
{
Util.TraceLine ("ItTaskProc: Thread aborted");
}
catch (Exception ex)
{
Util.TraceLine ("ItTaskProc: Exception catched: " + ex);
}
finally
{
_itTaskEvent.Reset ();
}
Util.TraceLine ("ItTaskProc ended gracefully");
}

public bool CommandReceivedHandler (object sender, TcpInfoEventArgs
tcpInfo)
{
bool continueReading = true;

Util.TraceLine
("CommandCoordinator:CommandReceivedHandler tcpInfo = " + tcpInfo);
return continueReading;
}

private void CloseApp ()
{
_itTaskEvent.Set ();
_tcp.Close ();
}

private void buttonOK_Click(object sender, System.EventArgs e)
{
CloseApp ();
Application.Exit ();
}

Tcp.cs
------

using System;

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Text;

namespace IPRManaged
{
// publish/subscribe to export received command
// ---------- TcpInfoEventArgs ----------

public class TcpInfoEventArgs : EventArgs
{
private byte [] _buffer;
private int _bytesRead = 0;

public TcpInfoEventArgs (byte [] buffer, int bytesRead)
{
_buffer = buffer;
_bytesRead = bytesRead;
}

public override string ToString()
{
return "TcpInfoEventArgs #read = " + _bytesRead;
}

public int BytesRead
{
get { return _bytesRead; }
}

public byte [] Buffer
{
get { return _buffer; }
}
}

public class Tcp
{
private const int PORT = 1414;
private Socket _server;
private Thread _listeningThread = null;
private bool _mustRun = true;
private bool _continueReading = true;

// publish/subscribe to export received command
public delegate bool CommandReceivedHandler (object sender,
TcpInfoEventArgs tcpInfo);
public event CommandReceivedHandler OnCommandReceived;

// Thread signal.
private static ManualResetEvent _allDone = new ManualResetEvent
(false);
public Tcp ()
{
_listeningThread = new Thread (new ThreadStart (RunServer));
_listeningThread.Name = "TCP Listening thread";
_listeningThread.Start ();
}

public void Close ()
{
_mustRun = false;
_allDone.Set ();
// should not be needed
if (_listeningThread != null)
_listeningThread.Abort ();
}

public void RunServer ()
{
try
{
_server = new Socket
(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint (IPAddress.Any, PORT);
_server.Bind (iep);
_server.Listen (5);
Util.TraceLine ("TCP Server listening on port #" + PORT);

while (_mustRun)
{
// Set the event to nonsignaled state.
_allDone.Reset ();

_server.BeginAccept (new AsyncCallback (AcceptConnection),
_server);
// Wait until a connection is made before continuing.
_allDone.WaitOne ();
}
}
catch (Exception ex)
{
Util.TraceLine ("RunServer: Exception catched " + ex.Message);
}

_listeningThread = null;
Util.TraceLine ("RunServer: thread finished");
}

void AcceptConnection (IAsyncResult iar)
{
Socket server = (Socket) iar.AsyncState;
Socket client = server.EndAccept (iar);
Util.TraceLine ("TCP Server: connection accepted from client: " +
client.RemoteEndPoint.ToString() + " on " +
client.LocalEndPoint.ToString ());

// Signal the main thread to continue.
_allDone.Set ();

// Create the state object.
StateObject state = new StateObject ();
state.clientSocket = client;
Util.TraceLine ("Tcp:AcceptConnection: Accepting for client = " +
client.RemoteEndPoint.ToString () + " ...");
client.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback (ReadCallback), state);
}

public void ReadCallback (IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.clientSocket;
Util.TraceLine ("Tcp:ReadCallback: Receiving from client = " +
handler.RemoteEndPoint.ToString () + " ...");

try
{
// Read data from the client socket.
int bytesRead = handler.EndReceive (ar);

if (bytesRead > 0)
{
Util.TraceLine ("ReadCallback: " + bytesRead + " bytes received
for client = "
+ handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
StringBuilder iprlibIn = new StringBuilder ("IPRLIB:IN:");
for (int i = 0; i < bytesRead; i++)
{
iprlibIn.Append ("[" + i + "] = " + state.buffer .ToString
("X2") + " ");
}
Util.TraceLine (iprlibIn.ToString ());

if (OnCommandReceived == null)
Util.TraceLine ("TcpConnection:Run no subscriber defined to get
the command");
else
{
TcpInfoEventArgs tcpInfo = new TcpInfoEventArgs (state.buffer,
bytesRead);
_continueReading = OnCommandReceived (this, tcpInfo);
}

Util.TraceLine ("ReadCallback: continueReading = " +
_continueReading +
" for client = "
+ handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());

if (_continueReading)
handler.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback (ReadCallback), state);
}
else
{
Util.TraceLine ("ReadCallback: no byte read, stop reading");
handler.Shutdown (SocketShutdown.Both);
handler.Close ();
handler = null;
}
}
catch (Exception ex)
{
Util.TraceLine ("ReadCallback: Exception catched: " + ex.ToString
());
}

if (handler != null)
Util.TraceLine ("ReadCallback: handling finished for client = "
+ handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
}

public static void SendCallback (IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket) ar.AsyncState;

// Complete sending the data to the remote device.
int bytesSent = handler.EndSend (ar);
Util.TraceLine ("SendCallback: Sent " + bytesSent + " bytes to
client = " +
handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
}
catch (Exception e)
{
Util.TraceLine (e.ToString());
}
}
}

// ---------- StateObject ----------

// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket clientSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte [BufferSize];
}
}

Logs (see the problem between 10:09:39:015 and 10:09:42:500)
----

....
10:09:38:984: ItTask thread: before WaitOne
10:09:39:000: ItTask thread: after WaitOne
10:09:39:000: ItTask thread: before ItTaskProc
10:09:39:000: ItTask thread: _serialChannel.ItTask ()
10:09:39:000: ItTask thread: after ItTaskProc
10:09:39:000: ItTask thread: dtCurrent=10:09:39:000: ,
dtLast=10:09:38:968:
10:09:39:000: ItTask thread: before WaitOne
10:09:39:015: : Tcp:ReadCallback: Receiving from client =
127.0.0.1:3417 ...
10:09:42:500: ItTask thread: after WaitOne
10:09:42:515: ItTask thread: before ItTaskProc
10:09:42:515: ItTask thread: _serialChannel.ItTask ()
10:09:42:515: ItTask thread: after ItTaskProc
10:09:42:515: ItTask thread: dtCurrent=10:09:42:515: ,
dtLast=10:09:39:000:
10:09:42:515: ItTask thread: New maximum ItTaskElapsedTime =
00:00:03.5156250
10:09:42:531: ItTask thread: before WaitOne
10:09:42:531: : ReadCallback: Exception catched:
System.Net.Sockets.SocketException: Une connexion existante a dû être
fermée par l'hôte distant
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at IPRManaged.Tcp.ReadCallback(IAsyncResult ar) in
c:\temp\testipr\windowsapplication\tcp.cs:line 157
10:09:42:531: : ReadCallback: handling finished for client =
127.0.0.1:3417 on 127.0.0.1:1414
10:09:42:531: : Tcp:ReadCallback: Receiving from client =
127.0.0.1:3416 ...
10:09:42:531: : ReadCallback: Exception catched:
System.Net.Sockets.SocketException: Une connexion existante a dû être
fermée par l'hôte distant
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at IPRManaged.Tcp.ReadCallback(IAsyncResult ar) in
c:\temp\testipr\windowsapplication\tcp.cs:line 157
10:09:42:531: : ReadCallback: handling finished for client =
127.0.0.1:3416 on 127.0.0.1:1414
10:09:42:546: ItTask thread: after WaitOne
10:09:42:546: ItTask thread: before ItTaskProc
10:09:42:546: ItTask thread: _serialChannel.ItTask ()
10:09:42:546: ItTask thread: after ItTaskProc
10:09:42:546: ItTask thread: dtCurrent=10:09:42:546: ,
dtLast=10:09:42:515:
....
 
D

Droopy Toon

Am I the first to meet this problem ?
Please give me some help.

Thanks in advance,

Pierre.
 
D

Droopy Toon

OK, I tried to do that (removing unneeded lines to keep the thread as
short as possible) but it seems I failed to do that.
I try with pastebin and complete code.

I created 2 solutions :

1) server (win application)

Main form class : http://pastebin.ca/2936
TCP server class : http://pastebin.ca/2934

2) client (win application)

TCP Client class : http://pastebin.ca/2943

I start the server.
Then, I start the client in debug mode and stop it (with "Debug->Stop
Debugging")

An exception is raised (and catched) in the server but the "ItTaskProc"
thread is "freezed" for more than 3 seconds see the logs (between line
63 and line 64) here : http://pastebin.ca/2944)

Thanks in advance for your help.

P.S (I created the client code just to cause the problem, I know it
should make some "resources cleaning" but as I use "Stop Debugging" to
stop it ...)
 
W

Willy Denoyette [MVP]

Droopy Toon said:
OK, I tried to do that (removing unneeded lines to keep the thread as
short as possible) but it seems I failed to do that.
I try with pastebin and complete code.

I created 2 solutions :

1) server (win application)

Main form class : http://pastebin.ca/2936
TCP server class : http://pastebin.ca/2934

2) client (win application)

TCP Client class : http://pastebin.ca/2943

I start the server.
Then, I start the client in debug mode and stop it (with "Debug->Stop
Debugging")

An exception is raised (and catched) in the server but the "ItTaskProc"
thread is "freezed" for more than 3 seconds see the logs (between line
63 and line 64) here : http://pastebin.ca/2944)

Thanks in advance for your help.

P.S (I created the client code just to cause the problem, I know it
should make some "resources cleaning" but as I use "Stop Debugging" to
stop it ...)


The ItTask thread is suspended but also the ReadCallback thread[1], so it
looks like all (managed ?) threads are blocked.
However, the problem doesn't show up when I ran your code, so I would start
to look at some external cause. Things I realy like to knwo are; available
free memory and CPU resources(usage pattern), OS version, .NET version.

Willy.


[1]Message should follow 63 within a max of two thread quota limits.
063 14:15:51:859: : Tcp:ReadCallback: Receiving from client = 127.0.0.1:4363
....
.....
071 14:15:55:093: : ReadCallback: Exception catched:
System.Net.Sockets.SocketException: Une connexion existante a dû être fermée
par l'hôte distant
 
D

Droopy Toon

It doesn't show up for you !
It is amazing !

I have an almost new PC (512 MB memory (more than 150 MB free according
to task manager), Win XP Professional 5.1.2600 SP1, Pentium 4 2.8GHz,
..NET Framework 1.1.4322, Visual Studio 7.1.3088).

Thanks for your help.
 
J

Jon Skeet [C# MVP]

Droopy Toon said:
OK, I tried to do that (removing unneeded lines to keep the thread as
short as possible) but it seems I failed to do that.
I try with pastebin and complete code.

I created 2 solutions :

1) server (win application)

Main form class : http://pastebin.ca/2936
TCP server class : http://pastebin.ca/2934

2) client (win application)

TCP Client class : http://pastebin.ca/2943

I start the server.
Then, I start the client in debug mode and stop it (with "Debug->Stop
Debugging")

An exception is raised (and catched) in the server but the "ItTaskProc"
thread is "freezed" for more than 3 seconds see the logs (between line
63 and line 64) here : http://pastebin.ca/2944)

That sounds like it could well be the huge performance penalty you get
the first time an exception is thrown *but only if you're running in a
debugger*.

Try throwing and catching the same exception before you do anything
else - you'll see the same freeze then, but not later on. None of this
matters outside the debugger though.
 
D

Droopy Toon

I think it doesn't show up because you don't stop the client "abruptly"
as I am doing (using "Stop Debugging").
Can you try in the same environment as me ?

Droopy.
 
W

Willy Denoyette [MVP]

I am stopping the client abruptly, I'm killing the client's process.
I would prefer you do the same, because I don't like the managed debugger to
interfere with the process.

And this is the debug output (dbgview.exe)

00001870 16.48774802 [236] 15:52:46:340: ItTask thread: before WaitOne
00001871 16.50030688 [236] 15:52:46:350: : Tcp:ReadCallback: Receiving from
client = 127.0.0.1:2997 ...
00001872 16.51107780 [236] 15:52:46:370: ItTask thread: after WaitOne
00001873 16.51112781 [236] 15:52:46:370: ItTask thread: before ItTaskProc
00001874 16.51117586 [236] 15:52:46:370: ItTask thread:
_serialChannel.ItTask ()
00001875 16.51122447 [236] 15:52:46:370: ItTask thread: after ItTaskProc
00001876 16.51126554 [236] 15:52:46:370: ItTask thread:
dtCurrent=15:52:46:370: , dtLast=15:52:46:340:
00001877 16.51129012 [236] 15:52:46:370: ItTask thread: before WaitOne
00001878 16.54410100 [236] 15:52:46:400: ItTask thread: after WaitOne
00001879 16.54414877 [236] 15:52:46:400: ItTask thread: before ItTaskProc
00001880 16.54418955 [236] 15:52:46:400: ItTask thread:
_serialChannel.ItTask ()
00001881 16.54423705 [236] 15:52:46:400: ItTask thread: after ItTaskProc
00001882 16.54427700 [236] 15:52:46:400: ItTask thread:
dtCurrent=15:52:46:400: , dtLast=15:52:46:370:
00001883 16.54709775 [236] 15:52:46:400: ItTask thread: before WaitOne
00001884 16.55660985 [236] 15:52:46:410: : ReadCallback: Exception catched:
System.Net.Sockets.SocketException: An existing connection was forcibly
closed by the remote host
00001885 16.55660985 [236] at
System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
00001886 16.55660985 [236] at IPRManaged.Tcp.ReadCallback(IAsyncResult
ar)

Notice the delay between event 1871 and 1884, the first is the time at which
the client detects the remote side dropped the connection, the latter is the
moment the exception handler runs. This delay (16.55660985 - 16.50030688 =
55.36 msec.) is due to the fact you are running the ItTask at highest
priority (which you shouldn't do on a single CPU box).
If you run this thread at normal priority, the exception handling takes less
than 2 msec.

Are you running both client and server in the VS debugger?
Willy.
 
D

Droopy Toon

Yes I was running both client and server in the VS debugger.
I tried with dbgview.exe for both client and server : the problem
doesn't show up (I mean no socket exception catched).
I also tried to run both client and server in the VS debugger, then kill
the client with the task manager : no socket exception catched in this
case.
I also tried to start the server with dbgview.exe, the client with VS
debugger then Stop Debugging : I got a socket exception but with no time
penalty !
So it seems my problem is really linked to the use of VS debugger.

Thanks a lot for your help,

Droopy.
 
R

Ravichandran J.V.

One could be because of the priority set for a thread. Two could be due
to the asynchronous nature of the call. The WaitOne or the EndInvoke (I
didn't go through the whole code) waits for the called function to
complete its execution and hence, the delay or the freeze(possibly!).

with regards,


J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- http://www.411asp.net/func/search?
qry=Ravichandran+J.V.&cob=aspnetpro
- http://www.southasianoutlook.com
- http://www.MSDNAA.Net
- http://www.csharphelp.com
- http://www.poetry.com/Publications/
display.asp?ID=P3966388&BN=999&PN=2
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com
 
W

Willy Denoyette [MVP]

Ravichandran J.V. said:
One could be because of the priority set for a thread. Two could be due
to the asynchronous nature of the call. The WaitOne or the EndInvoke (I
didn't go through the whole code) waits for the called function to
complete its execution and hence, the delay or the freeze(possibly!).


Why don't you read the other replies before replying?

Willy.
 
D

Droopy Toon

I forgot to mention that I have a Pentium 4 2,8 GHz with HyperThreading
so changing thread priority to Normal does not help.

Droopy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top