Threading Faux Pa

R

russ.haley

Threading and suspend

I have an application that will load x number of "communicators". These
"communicators" start up a communications channel with another
application(of no importance). The initial code loaded the object
model and then initialized the communications on the same thread, which
took a lot of time. It took a minute plus to load four or five
communicators.

I found that if I can move the communications loading to another thread
it greatly improves the overall load time to about 10 seconds for 100
communicators. The problem was when I realeased the thread, the
objects were destroyed too. Most noteably the Asynchronous call back
for a NetworkStream. I found that if I suspend the thread, all the
objects stay around and processing continues fine and performs quite
well, but I am uncertain about leaving a thread just "hanging" there
suspended. In the dispose method of the parent object, I simple resume
the thread if it's suspended and everthing seems to exit cleanly.

Is suspending a thread and using the objects it creates an acceptable
threading methodology? Do the Asynchrounous callbacks use the suspended
thread or the main thread? Any insight would be helpful. A breif
example below...

Thanks in Advance
Russ

Class Parent
{
private Thread _thrMyThread;

private MyTCPClientWrapper _clsMyWrapper;

public Parent()
{ //The object model needs to be loaded before the constructor
exits
LoadObjectModel();
_thrMyThread = new Thread(new ThreadStart(InitCommunications));
_thrMyThread.Start();
}

private void LoadObjectModel()
{
//Load Object here
_clsMyWrapper = new MyTCPClientWrapper("args");
}

private void InitCommunications()
{
//Load _clsMyWrapper Here

_thrMyThread.Suspend();
}

public void Dispose()
{
if(_thrMyThread.ThreadState == ThreadState.Suspended)
{
_thrMyThread.Resume();
}
}
}
 
J

Jon Skeet [C# MVP]

Threading and suspend

I have an application that will load x number of "communicators". These
"communicators" start up a communications channel with another
application(of no importance). The initial code loaded the object
model and then initialized the communications on the same thread, which
took a lot of time. It took a minute plus to load four or five
communicators.

I found that if I can move the communications loading to another thread
it greatly improves the overall load time to about 10 seconds for 100
communicators. The problem was when I realeased the thread, the
objects were destroyed too. Most noteably the Asynchronous call back
for a NetworkStream.

Could you give a short but complete example of what you mean? I suspect
there's a better way round this - Thread.Suspend is definitely not a
good way to go.

Asynchronous callbacks use thread pool threads, btw.

Jon
 
G

Guest

Seems that something wrong with methods that called by thread. As Jon said
it's insufficient info to find the problem

Threading and suspend
I have an application that will load x number of "communicators". These
"communicators" start up a communications channel with another
application(of no importance). The initial code loaded the object
model and then initialized the communications on the same thread, which
took a lot of time. It took a minute plus to load four or five
communicators.

I found that if I can move the communications loading to another thread
it greatly improves the overall load time to about 10 seconds for 100
communicators. The problem was when I realeased the thread, the
objects were destroyed too. Most noteably the Asynchronous call back
for a NetworkStream. I found that if I suspend the thread, all the
objects stay around and processing continues fine and performs quite
well, but I am uncertain about leaving a thread just "hanging" there
suspended. In the dispose method of the parent object, I simple resume
the thread if it's suspended and everthing seems to exit cleanly.

--
WBR,
Michael Nemtsev :: blog: http://spaces.msn.com/laflour

"At times one remains faithful to a cause only because its opponents do not
cease to be insipid." (c) Friedrich Nietzsche
 
R

russ.haley

/*
Hmmm... I'm not sure how much I can give you in a 'brief' description.
:)

Esentially, there is a collection of objects like the parent object in
my first post. When the application starts up, The collection grabs all
the Parent class data from the database and loads all the objects.
After all the objects are loaded, the collection then loops through all
the objects in the collection and starts the communications - Lets say
a TCPClient that is wrapped in a 'communicator' class. We are not
limited to TCPClient, (i.e. we have a serial driver, a TCPServer
communicator, a dialup communicator etc) but it seems to be the most
sensitive because it's uses the BeginRecieve callback method. As I
mentioned, if everything is processed synchronously, loading takes a
considerable amount of time. I added a thread (_thrMyThread) to the
Parent class that gets started and loads the communicator and then
suspends - as expressed in LoadCommunicator() and InitComms(). Moving
the communications loading to the new thread improved load times
tremendously.Unfortuantely, I really don't think this is the best
solution and I am running into thread abort errors (i.e. if the comms
are still busy when _thrMyThread ends, exceptions are thrown).

Logic Flow:

1) Start the collection
2) Load all the 'Parent' objects
3) Begin loading communications
4) In LoadCommunicator, start a thread and launch the communicator
initialization and startup on the thead, then suspend it when complete
5) When exiting a parent object call dispose, which resumes the
thread - causing it to terminiate.


NOTES:
1) I hand coded this so any syntax errors are not important, the real
code compiles...
2) Any missing class members are un-important, just pretend you know
what they are...
3) ParentCollection just extends CollectionBase and returns Parent
objects
4) Syntax is a little messy as I inherited the real code form some that
did think standard
syntax or error handling is important :-{

Hope this is a little more explicit

Russ
p.s. Please feel free to email me directly if you need more info...
*/

public class ObjectModelController
{
ParentCollection _pcMyColl = new ParentCollection();

public ObjectModelController()
{

Parent objParent;

DataReader reader = MakeBelieveGetDataFunction();

//Loop through data and Create all instances of Parent object
while(reader.Read())
{
objParent = new Parent(reader[0],reader[1],reader[2]);

_pcMyColl.Add(objParent);
}

//This is where we load the communications. This part of the
processing is what takes so long
// if done synchronously
for(int i = 1; i <_pcMyColl.Count; i++)
{
//Loads defaults and comms settings
_pcMyColl.LoadCommunicator();
}
}

public void Shutdown()
{
for(int i = 1; i < _pcMyColl.Count; i++)
{
_pcMyColl.CloseComms();

_pcMyColl.Dispose();
}
}
}

/******************************************************************************************/
public class Parent
{
private Thread _thrMyThread;

private MyTCPClientWrapper _clsMyWrapper;

private MyCommsWrapper _cwCommunicator;
public Communicator
{
get
{return _cwCommunicator;}
set
{_cwCommunicator = value;}
}

public Parent()
{ //The object model needs to be loaded before the constructor
//exits
LoadObjectModel();
}

private void LoadObjectModel()
{
//Load Object here
}

private void LoadCommunicator()
{
//Load the thread object and start it
_thrMyThread = new Thread(new
ThreadStart(InitCommunications));
_thrMyThread.Start();
}

//This is called by the thread that is started in the
LoadCommunicator Function
private void InitCommunications()
{
this.Communicator = new MyCommsWrapper("args");

if(this.Communicator.ConnectOnStartup)
{
this.Communicator.StartComms();
}

//stops the thread from dropping out and finishing
_thrMyThread.Suspend();
}

public void Dispose()
{
if(_thrMyThread.ThreadState ==
ThreadState.Suspended)
{
_thrMyThread.Resume();
}
}
}
/*****************************************************************************************/
public class Communicator
{
public CommsProfile profile;

public bool ConnectionStatus;

public Communicator(string strArgs)
{
profile = new CommsProfile("args");
}
public abstract void AsyncWrite(string strMessageOut);
public abstract void StartComms();
public abstract bool CloseComms();

}

/************************************************************************************************/

public class TCPClientCommunicator: Communicator
{
TCPClient _tclClient;
NetworkStream _nsTCPStream;

public TCPCLientCommunicator(string strArgs)
{
//LOAD PROFILE HERE (ip, port, timeout)
profile = new TCPClientProfile('127.0.0.1', 8080, 600);
}

public override void StartComms()
{
_tclClient = new TcpClient(this.profile.ipAddress,
this.profile.portNumber);
LingerOption loDontLinger = new LingerOption(false,0);
_tclClient.LingerState = loDontLinger;

_nsTCPStream = _tclClient.GetStream();

_nsTCPStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE, new
AsyncCallback(DoRead), null);

CommStatusUpdate("Open");
this.ConnectionStatus = true;
}

private void DoRead (IAsyncResult ar)
{
int intCount;
try
{
if(_nsTCPStream != null)
{
lock(_nsTCPStream)
{
intCount = _nsTCPStream.EndRead(ar);
if (intCount < 1)
{
return;
}
//BuildString concatinates the data and then uses an event to send out
// data to other parts of the application then clears the buffer.
BuildString(readBuffer, 0, intCount);
_nsTCPStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE,new
AsyncCallback(DoRead), null);
}
}
}
catch (Exception ex)
{
l4nSystemLogger.Error(System.Reflection.MethodInfo.GetCurrentMethod().Name,
ex);
Debug.WriteLine(ex.Message);
}
}

public override AsyncWrite(string strMessage)
{
_tclClient.Write(strMessage);
}


public override bool CloseComms()
{
try
{
//If the client is valid...
if (_tclClient != null)
{

//Close and destroy the stream
_nsTCPStream.Close();
_nsTCPStream = null;

//Close and destroy the TCPClient
_tclClient.Close();
_tclClient = null;

//Turn Connection status to false -
this.ConnectionStatus = false;
CommStatusUpdate("Closed");

//THIS IS A BAND_AID THAT Pauses the processing
until
//the comms can close. Doesn't always work though.
Sometimes comms takes
// longer to close than the time I have set...
// I want a better way to do this
_thrMyThread.Join(500);
}
}
catch (Exception err)
{
System.Console.WriteLine(err.Message);
}
return true;
}

}
 
R

russ.haley

p.s.: Anybody know of a good book on threading in C# that has LOTS of
good examples?

Cheers!
Russ
 
J

Jon Skeet [C# MVP]

/*
Hmmm... I'm not sure how much I can give you in a 'brief' description.
:)

What I'm really after is a short but complete program (ready to run -
one that compiles straight away) which demonstrates the thread abort
etc that you're seeing. That's the part I don't understand...
 
G

Guest

1. "CSharp Threading Handbook" - gives a basis
2. "Manning - .NET Multithreading" - more wide description

p.s.: Anybody know of a good book on threading in C# that has LOTS of
good examples?

--
WBR,
Michael Nemtsev :: blog: http://spaces.msn.com/laflour

"At times one remains faithful to a cause only because its opponents do not
cease to be insipid." (c) Friedrich Nietzsche
 
N

Nick Hounsome

Threading is not something to learn by example because it is too easy to
write incorrect code that seems to work.

I'm not saying that examples are bad, just that you really do need to
understand rather than merely copy when it comes to threading.
 
R

russ.haley

I fully agree. Unfortunatley I have enough theory to be dangerous but
not enough implementation experience to know what is and isn't a good
idea. That's where examples of different implementation scenarios would
be really handy. Either way, any suggestions on good books that deal
with threading?
 

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