[.net] Thread Safe Socket,

Started by
5 comments, last by phb5000 17 years, 10 months ago
I have a class which is a simple socket wrapper. It does all the async work with the socket, receives data, etc... This class is then used by another class by hooking events that i declared in my wrapper. Now, if the class that uses the wrapper is for example a form I of course get the Cross-Thread Operation not valid... Is there any way of making the socket wrapper thread safe (the events) so that the class using the wrapper doesnt have to worry about threads, at all!?
Advertisement
you need to invoke back to the thread where the form lies to change the form (and its components)

you might want to write your code to do something like the following when you want to update a form in an event that was fired from another thread: (this is off the top of my head, and uses anonymous delegates from c# 2.0, so it may not work, but should give you a good idea where to start looking)

if (txtData.InvokeRequired){	txtData.Invoke( delegate { txtData.text = "Updated from another thread, using invoke"; } );}else{	txtData.Text = "Same Thread. No invoke needed.";}


if you are using c# 1.0, you'll have to make an delegate to call back to, and masrash back to the forms thread.
So there is no way of handling the multithreading only within my component (the socket wrapper)? I have to add the "usage" code to use the data generated by my component.

And another question what if my application looks like this:

THE WINDOWS APPLICATION (GUI) (Thread 1)
|
|
|
APPLICATION FEATURES (Stuff my app does) (Thread 1)
|
|
|
DATA PARSER AND COMMUNICATOR (Communication Parser) (Thread 1)
|
|
|
SOCKET WRAPPER (Wraps the socket capabilites supplied by .NET) (Thread 2)

Now, the only transition between threads is between the socket wrapper and the data parser, however, the only place that I can do the thread switching is in the actual windows application (use invoke...) But that seems like a very bad thing to do since the number of events at each step increase.

For example:
the socket wrapper may have 3 events (connect, close, received)
the data parser may have a couple more (connect, close, recievedType1, Type2)
application features may have a lot more (this happened, this, this, this, specifically for each type of command received through the socket).

SO, what im trying to say is that, isnt there some way of doing the thread switch at a very low level so that the amount of work that has to be done, regarding threads, at the highest level would be nothing.

Why do thread switching for maybe 20 events at the windows application level, when it maybe could be done at the lowest level with only 3 events.


[Edited by - phb5000 on June 13, 2006 2:29:30 PM]
Mono/GTK2 has a static method called Gtk.Application.Invoke(), that is used to switch to the GUI thread.

I'm not sure if System.Windows.Forms has a similar construct, though you might be able to make one if it doesn't (a small public class in the main window, that exposes Invoke simply for the purpose of getting back to the main gui thread). Then fire event within a delegate, insuring that down the event chain they are in the proper thread.

A sloppy solution would be to make the instance of your main windows form public, then use Form.Invoke() within your socket wrapper.
Could you please be a bit more specific maybe on how to actual implement an invoke method? What exactly does it do? How exactly do I get back to the main thread without using the invoke method supplied by a windows control?
using System;using System.Threading;using System.Collections;using System.Windows.Forms;namespace InvokeTest{	class MyForm : Form	{		public TextBox txtTest;		public Button btnTest;			public MyForm()		{			this.Text = "Test Threads";						this.btnTest = new Button();			this.btnTest.Text = "Click";			this.btnTest.Top = 35;			this.btnTest.Left = 5;			this.btnTest.Click += new EventHandler(btnTest_Click);						this.Controls.Add(btnTest);						this.PerformLayout();			this.ResumeLayout(false);		}				private void btnTest_Click(object sender, EventArgs e)		{			Thread x = new Thread(new ThreadStart(MyThreadClass.Run));			x.Start();		}	}	class MainClass	{		private static MyForm frmTest;				[STAThread]		public static void Main(string[] args)		{			frmTest = new MyForm();						Application.Run(frmTest);			Console.WriteLine("Hello World!");		}						public static void Invoke(EventHandler x)		{			frmTest.Invoke(x);		}					}		public class MyThreadClass	{		public static void Run()		{			Console.WriteLine("Working!");			Thread.Sleep(5000);						MainClass.Invoke( delegate {				//Thread.Sleep(5000);				Console.WriteLine("Thread done!");			} );		}	}}


i just wrote this in like 10 minutes, and I am on a FC5 system right now (so I am using MonoDevelop/Mono, whose System.Windows.Forms is far from perfectly compliant) but that might give you an idea of how to invoke back to the primary forms thread.

But anyway, by changing the position of the Sleep from outside the delegate to inside the delegate, you'll see which thread you're working in.

Obviously, outside the delegate the new thread sleeps for 5 seconds, inside the delegate the form thread should sleep for 5 seconds (and the UI will become unresposive). This also demonstrates why you'd really want to invoke back to the main thread at the last second, only when you needed to do some work on the main thread.
I managed to get a completely thread safe socket wrapper by simply using the BackgroundWorker component supplied by the .net framework.

This topic is closed to new replies.

Advertisement