Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hi,

 

I'm quite new to the idea of threading and was wondering what was the best way to handle the following...

 

I have an application that is going to accept socket connections from various other remote devices. I want to create a new thread to handle each of these connections. I'm OK, I think, on how to do that, it's just the best way to handle the threads to keep track of them, for example if another message comes in from one remote device, I need to route that message to the correct thread for processing. What would be the best way to handle that?

 

Any suggestions appreciated.

 

Also as a side note, this may be a really stupid question, but if I have and application with a form and a class, how do I update controls (i.e.: textboxes) on that form from my class? I can't seem to reference them.

 

BTW I'm working in C# but I'm familiar with VB also.

 

Thanks in advance for any assistance.

 

Mark

Posted

Create an array of threads, everytime you create a thread, add it to the array.

 

If you need to update controls on a form from a seperate class, the design may be flawed. Do you have a parent form? A form is a class, you access the controls on a form as you do properties of any other class.

Posted
Create an array of threads, everytime you create a thread, add it to the array.

 

If you need to update controls on a form from a seperate class, the design may be flawed. Do you have a parent form? A form is a class, you access the controls on a form as you do properties of any other class.

 

Thanks for the reply Diesel.

 

I didn't expect it to be as simple as that.

 

In regards to the form thing, I'm looking at other ways of dealing with that.

 

Thanks again.

Posted
Thanks for the reply Diesel.

 

I didn't expect it to be as simple as that.

 

In regards to the form thing, I'm looking at other ways of dealing with that.

 

Thanks again.

 

Hmmmm it isn't as easy as I thought! :confused:

 

The idea has changed slightly from how I first planned so maybe this impacts how it works..

 

I have a single application that will accept connections from remote devices. I want this application to create a new thread for each connection to process the messages. I want the main process to still receive the messages and send them on to the correct thread for processing. The problem is how can I do that?

 

For example I have 5 threads (in this case they have started a form) and I want to say, set a value on thread 3 because I received a message from remote connection 3. How would I do that.

 

Any explanation would be appreciated, as I'm not sure if I can actually do what i want to do.

 

Thanks again.

Posted

I'm just curious, why do you want all 'device 3' messages be handled by 'thread 3'?

A thread in itself has no state, it basicly is nothing more than a callstack. I could understand it if you wanted 'device 3' messages be handled by 'handler 3', where 'handler 3' would be an object with a state specific to that device. It is also a lot easier to send calls to a specific object, than a thread. You only need a unique identifier with each call (like a sender object) and a lookup mechanism from ID to 'handler' (you can do this with for instance a hashtable)

Off course 'handler 3' can start handling the message on a separate thread that is taken from the .net framework threadpool when necessary, but then returned to the pool when finished. But this doesnt glue 'handler 3' to that specific thread.

 

With a 'thread3' mechanisme, you'd have to make some kind of message pump that keeps active by waiting for a new message to be handled, but also put in a queue in case 2 messages are received in very short order, before the first message could be completely handled. Sounds like a lot of work to me.

Nothing is as illusive as 'the last bug'.
Posted
Yeh, if your receiving the messages synchronously, then you don't need threads. And as wile said, what you described was storing the state of the devices, just use a regular class for that. You could always attach events to certain properties of the class.
Posted (edited)
Yeh' date=' if your receiving the messages synchronously, then you don't need threads. And as wile said, what you described was storing the state of the devices, just use a regular class for that. You could always attach events to certain properties of the class.[/quote']

 

Thanks for your replies.

 

I think I've got a model working of what I'm after.

 

I create a new class object and execute it on a seperate thread. This class object will be used to process messages to that class (i.e.: object 1 processes object 1 messages etc.).

 

I wanted them to be as seperate classes as they need to be processed asynchronously, as any number of users could be doing different things at any one time.

 

I am new to this sort of stuff, and as a newbie, I'm trying to fight my way through it. Maybe this isn't the best approach, but I suppose I'll only find that out later down the line.

 

I've attached the code for you to look at (please ignore the mess). The sln file is under the client folder. The idea being, that you execute the Kernel EXE, which start the main Client EXE process. Connections are simulated by clicking the AddClient button. It's very simplistic functionality wise, but I wanted to try to prove a concept.

 

I just need to figure out the process of getting information back from the clients to the Kernel now.

 

Regards,

 

Mark

DEMO.zip

Edited by PlausiblyDamp
Posted

One thing is a big no no:

 

this loop in runlistener in clsKernel.

 

while ( !stopListen)
{
 if ( listener.Pending())
 {
  //connection code 
 } 
 Thread.Sleep( 1000);
}

What you have here is called a 'busy wait'.

The Pending method is not blocking. This means that you keep the cpu busy while waiting, repeating the while loop over and over again until finally Pending returns true. Now you make live a little bit easier for the cpu with the sleep statement but that actually just adds to the problems. Because now, incoming calls can get up to 1000 millisecond delay before they are even handled, for chat-applications this can be acceptable (who can see the other one typing 100 miles away, for other applications where the user can see when the original message is send and when it is received, this is unaccaptable.

However, the AcceptTcpClient method you have in your code is the sollution to that problem. The AcceptTcpClient only returns after it can return a tcpclient, so that would remove the busy wait loop. You can just call AcceptTcpClient and it will only return when it actually has something to return.

 

However, that generates another problem: you can't stop the loop as the check for stopListen is never executed if no client connects. This can easily be solved in the Stop method:

public void Stop()
{
 // wait for listen/dispatch thread to stop
 if ( !stopListen)
 {
   stopListen = true;
   listenThread.Join();
   //some more code

Remove the stopListen would mean changing the if to look directly at the threadstate of the listenThread, and to directly abort the thread itself.

so you get

//we dont have the stopListen variable anymore so we have to look
// at the thread to see what it is doing.
if ((listenThread.ThreadState != ThreadState.AbortRequested) &&
   (listenThread.ThreadState != ThreadState.Aborted))
 {
   listenThread.Abort();
   listenThread.Join();
//more code

That means you abort the thread. You still need the join statement to wait until the abort is finished.

 

When the abort method is called it will raise a ThreadAbortException in your RunListener method. So add an error handler that will catch this exception and call the listener.Stop() method.

 

As the whole stopListener has become pretty much useless, you can even remove that variable. This does mean you have to change the while loop. Here you can use the same mechanism as message pumps in good old c++ days have used: for ( ; ; ) this generates an infinite loop. However, remember that the abort method throws an exception, that exception will ensure that we can exit the loop.

 

So adding all this together your RunListener becomes something like:

void RunListener()
{
  //these two must be defined outside the try statement, because the listener
 // is also used in the catch.
 System.Net.IPAddress localAddr = System.Net.IPAddress.Parse("127.0.0.1");
 TcpListener listener = new TcpListener( localAddr, 1234);
 try
 {
   listener.Start();
   for(;;)
   {
     // accept new client
     ClientState newClient = new ClientState( listener.AcceptTcpClient());
     // add to our list of clients
     AddClient( newClient);
     // start listening for the client
     ListenClient( newClient);
   }
 }
 catch(ThreadAbortException ex)
 //maybe not only for a threadabortexception, but for all exceptions?
 {
   listener.Stop();
 }
}

If i'm correct, the ListenClient method will start listening to the socket, and it will call ExecuteMessage when something is received.

Although this is async, it isnt send to a specific thread, but is handled by the clsKernel in asynchronuous mechanisme. This means you have no control over which thread is used, the .NET framework takes it out of its pool threads, executes your code, then returns the thread back to the pool -> good, less worry/work for you ;).

 

Note that the ClientState object you have created is already specific per client. This also means that in the ExecuteMessage, where you retrieve that ClientState object from the IAsyncResult, you know through that ClientState, what client send the message.

 

hmm, it is pretty late (watching Formula 1 qualification at the same time, 0:00 -> midnight) so I hope this all makes sence ;).

Nothing is as illusive as 'the last bug'.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...