How do I pass arguments to a Thread in .Net - c#

I have function along these lines:
public void view(string msg)
{
messagebox.show(msg);
}
.
.
I want to pass arguments to this it from a thread.. I'm using .Net 1.1. How can I do this?

For .NET 1.1 there is no direct way but to use an object having both the method and the state, in this example (modified from the MSDN sample), the ThreadState class is instanced and passed the desired state, then its method is called and made to use the passed state.
public class ThreadState {
private string msg;
// The constructor obtains the state information.
public ThreadState(string msg) {
this.msg = msg;
}
public void view() {
//Do something with msg
}
}
public class Example {
public static void Main() {
ThreadState ts = new ThreadState("Hello World!");
// Create a thread to execute the task, and then
// start the thread.
Thread t = new Thread(new ThreadStart(ts.view));
t.Start();
t.Join();
}
}
For .NET > 1.1 (original question didn't state version.)
You pass the argument in the Start method. You will receive an object which you need to cast back to the proper type.
Thread t = new Thread(view);
t.Start("Hello");
public void view(object msg)
{
string m = (string)msg;
//Use msg
}
Either that, or use a ParameterizedThreadStart delegate.

The ParamaterizedThreadStart delegate is not present in .NET 1.1 (2003) nor does thread.Start take an Object param in 1.1. However you could try something like:
dict[mythread.name] = myval; //dict is a class scoped variable.
mythread.Start();

There are various ways to do that. One is to use the ParameterizedThreadStart delegate, which allows passing a single parameter of type Object to the thread. Change your view method to accept Object, then cast Object to String inside the method.

Create a class, set your properties as arguments and run related function of the class.
Dim run = New Runner()
run.mile = 20
run.pace = "slow"
Thr.Start(run.Process())
Or you need to use a global scope variable. Unfortunately no other way for .NET 1.1

The first code snippet provided by Vinko is exactly what you need under .NET 1.x as the original Threading namespace offered no in-built mechanism for parameterizing _beginthread.
Thus, you create a state class which contains the data you need, as well as the method which will be used for the delegate in the "new Thread()" statement, as Vinko has shown.
I was about to tap out a sample, and then I saw his sample code. If it's "not working" it's worth being explicit as to why, because by the naked eye that code looks all too familiar.
One "spin" on this is to properly encapsulate the thread construction as well as the thread start/join behavior.
Another option is to use ThreadPool.QueueUserWorkItem(), which isn't quite the same and can result in poor ThreadPool performance if over-used.
Another option is to create a thread that is blocked on a signal, e.g. ManualResetEvent, which is set when a data member has been initialized. The target data member can be as simple as an object reference as shown above, or you could use an ArrayList, Queue or Stack object (with proper locking) to implement a sort of "queue processor" where work items can be enqueued and processed by a dedicated thread, and where the dedicated thread remains dormant (blocked waiting for a signal) until there is work available.

Related

Accessing WinForms Controls from a serial port in a class

First, the apology: I'm new to posting questions on this site, so I apologize for formatting or information errors.I have seen many answers to taking data from a serial port dropped on a form and using it to populate text boxes, graphs, etc. on the main form, using "Invoke" because the serial port is running in a different thread.
I am trying to "generalize" some comm stuff we use all the time in to a class (yes, the old VB6 programmer is trying to grow up :-) and I'm having issues. I can do some things if I force a form name in the main program.cs and use the same namespace for the class, but this sorta defeats the purpose. I've also tried adding an event on the "received" even of the serial port in the class to raise an event on the main form. The event tries to get raised but a cross thread exception occurs.
The code at this point is quite large, so I'll try to "outline" it. In simplistic form, assuming I have a for called "Form1" which contains a text box called textbox1 and a class called "SerialThing":
Form1:
SerialThing mySerialThing ;
Form1_Load:
mySerialThing = new SerialThing();
DisplayData()
Textbox1.Text = "You Got Data!";
SerialThing:
Static SerialPort myDevice;
Init()
myDevice = new SerialPort;
myDevice.DataReceived += new SerialDataReceivedEventHandler(devicePort_DataReceived);
devicePort_DataReceived()
this.Invoke(new EventHandler(DisplayData));
The above will work if the serial port is placed on the main form, but not if created inside the class.
Again, sorry if too complex, or too simplistic. I am looking for an "easy" way to do this, but keep the class "generalized" (ideally not have to have the workspace names match, etc).
-Vin
There are many, many ways to do this. I'll present the classic approach using a custom event, delegates, and Invoke(), as I think it's important to understand that process. Once you've got this down, you can jump to some of the newer approaches.
First, in your SerialThing() class, you declare a Custom event to pass out data when it is received:
class SerialThing
{
public delegate void DataReceivedDelegate(string data);
public event DataReceivedDelegate DataReceived;
static SerialPort myDevice;
public SerialThing()
{
myDevice = new SerialPort();
myDevice.DataReceived += new SerialDataReceivedEventHandler(myDevice_DataReceived);
}
void myDevice_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ... grab the data and place into a string called "data" ...
string data = "";
// raise our custom event:
if (DataReceived != null)
{
DataReceived(data);
}
}
}
Now, over in Form1, you subscribe to that custom event when you create the instance of SerialThing. Additionally, when that event is received, you marshal the call from the secondary thread to the main thread using InvokeRequired, Invoke, and a delegate:
public partial class Form1 : Form
{
SerialThing mySerialThing;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += new SerialThing.DataReceivedDelegate(mySerialThing_DataReceived);
}
private delegate void DataReceivedDelegate(string data);
void mySerialThing_DataReceived(string data)
{
if (this.InvokeRequired)
{
this.Invoke(new DataReceivedDelegate(mySerialThing_DataReceived), new Object[] { data });
}
else
{
textBox1.Text = data;
}
}
}
EDIT: In response to your comments below...
Think of a delegate as simply a "pointer to a method". When you execute the delegate, the associated method gets run.
The InvokeRequired() portion determines if the code is running in a different thread than the one that created the control. In this case, the control is the Form itself (this). If true is returned, then the event was received in a different thread. We then proceed to this.Invoke() line inside the true portion of the If block. Again this refers to the Form. Thus the Form is requesting to Invoke ("run") the passed delegate on the thread that created it (the main UI thread). We create a instance of the delegate that actually points to the same method we are already in resulting in a recursive call. The second parameter is simply an array of Object used to pass the parameters along with the delegate.
When Invoke() is run we end up re-entering the method because of the recursive call. At this point, however, the InvokeRequired() check will return false as we are now running in the main UI thread. Therefore we drop down into the false portion of the If statement where we update the TextBox. In this pattern it is safe to update an GUI controls in the else block of the If statement.
Note that a recursive call isn't necessary here. This is simply a style choice. We could have instead used a second "helper" function that the delegate pointed to, and Invoked that instead. The recursive approach reduces the number of methods required.
This is perhaps the most verbose approach to solving this type of problem. I like it, though, as it shows the flow of events and data, and movement between the threads.
We could shorten all the Form code to just this, using anonymous delegates:
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += delegate (string data)
{
this.Invoke((MethodInvoker)(delegate() { textBox1.Text = data; }));
};
}
I don't know about you, but as a former VB6 programmer myself, that just looks weird when you first see that type of thing.
I've also used components that I know have things running in different
threads, yet the "form code" has never had to use the delegate stuff,
so maybe there's something that can be buried into the class?
Yes, it's possible to bake some "magic" into a class so that it raises events already on the main UI thread, thus not requiring any Invoke() calls. One way to do this is thru using a SynchronizationContext.
Another possibility for approaching this type of problem would be to use a BackgroundWorker() control which has events such as ProgressChanged() and RunWorkerCompleted() that are raised in the main UI thread for you (they do the necessary invoking type stuff under the hood for you).

Update WinForm Controls from another thread _and_ class

I am making a WinForms program, which requires separate threads
For readability and maintainability, i have separated all non-GUI code out into different classes. This class also 'generates' another class, which does some processing. However, i have now run into the issue where i need to change a WinForms control (append a string to textbox) from a thread that was initiated in a different class
I have searched around, and found solutions for different threads, and in different classes, but not both and the solutions provided seem incompatible (to me)
This may be the biggest 'lead' however: How to update UI from another thread running in another class
Class Hierarchy example:
class WinForm : Form
{
...
Server serv = new Server();
}
// Server is in a different thread to winform
class Server
{
...
ClientConnection = new ClientConnection();
}
// Another new thread is created to run this class
class ClientConnection
{
//Want to modify winform from here
}
I understand that eventhandlers are probably the way to go, but i can't work out how to do so in this situation (I am also open to other suggestions ;) )
Any help appreciated
It does not matter from which class you are updating the form. WinForm controls have to be updated on the same thread that they were created on.
Hence, Control.Invoke, allows you to execute a method on the control on its own thread. This is also called asynchronous execution, since the call is actually queued up and executed separately.
Look at this article from msdn, the example is similar to your example. A separate class on a separate thread updates a list box on the Form.
----- Update
Here you do not have to pass this as a parameter.
In your Winform class, have a public delegate that can update the controls.
class WinForm : Form
{
public delegate void updateTextBoxDelegate(String textBoxString); // delegate type
public updateTextBoxDelegate updateTextBox; // delegate object
void updateTextBox1(string str ) { textBox1.Text = str1; } // this method is invoked
public WinForm()
{
...
updateTextBox = new updateTextBoxDelegate( updateTextBox1 ); // initialize delegate object
...
Server serv = new Server();
}
From the ClientConnection Object, you do have to get a reference to the WinForm:Form object.
class ClientConnection
{
...
void display( string strItem ) // can be called in a different thread from clientConnection object
{
Form1.Invoke( Form1.updateTextBox, strItem ); // updates textbox1 on winForm
}
}
In the above case, 'this' is not passed.
you can use backgroundworker to make your other thread,
it allow you to deal easily with your GUI
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

Writing to a label from a static function

I'm trying to do something that I thought would be easy but can't figure out how to write to a label inside my stating function.
public static void StartProcessing(object data)
{
lblError.Text = "Blah Blah"
}
I get the error "An object reference is required for the non-static field, method, or property..."
So I tried creating a new instance of the label and adding it to a new instance of a control (Panel) but the lblError isn't getting displayed
public static void StartProcessing(object data)
{
Panel Panel1 = new Panel();
Label lblError= new Label();
Panel1.Controls.Add(lblError);
lblError.Visible = true;
lblError.Text = "Blah Blah";
}
there must be an easy way to do this? Which i've overlooked..
The function is getting called as follows: If I change the above to not be static I get an error message on the second line below saying the same "An object reference is required for the non-static field, method, or property..." When this function isn't static?
public object LaunchNewProcess(object data)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(ProcessStatuses.StartProcessing),
new object[] {newProcess, allProcesses}
);
Pass the label to your static function when you call it:
public static void StartProcessing(object data, Label lblError)
{
lblError.Text = "Blah Blah"
}
Static functions don't have access to controls because the controls belong to the instance of the page (class).
Static means that all instances of a class share the same function or variable. So, an instance of a class has access to a static variable or function. However, since a static is not "aware" of any instances of the class, it cannot access the members of an instance. In fact, a static method or variable does not even require any instance of the class to exist, so how could it?
Removing the static key word from your function will also work, as others have mentioned, but I'm assuming you made it static for a reason.
EDIT
Alright, this is more complex.
So, you have some class that launches a bunch of threads, and you want it to display to the user if something went wrong? Well, your current approach is flawed because you cannot access controls of a page without the instance of the page. Also, I am not sure how this approach would fit within the page lifecycle.
Your best approach (sorry for lack of code, it's going to depend a lot on your implementation) could be something like this:
//do this before you start spawning threads
List<bool> successes = new List<bool>();
ThreadPool.QueueUserWorkItem(
new WaitCallback(ProcessStatuses.StartProcessing),
new object[] {newProcess, allProcesses, successes}
);
//you MUST wait for all your threads to complete before proceeding!
if(successes.Any(s => !s))
{
//update your error label
}
public static void StartProcessing(object data, Label lblError)
{
var dataArray = (object[3]) data;
//if there is an error
dataArray[2] = false;
}
What you want to do is actually quite difficult.
You want to create a page, start an asynchronous task, send the page to the user, and then update content on the page after the asynchronous job finishes.
The problem is that by the time the asynchronous task finishes the page has already been sent, and based on the way HTTP works once you've sent your response you're done; there's not more communicating with the client for you. You need to wait for the client to send another request if you want to update them.
This means that you need to have JavaScript code that is constantly polling the server basically asking, "Are you done yet, are you done yet, are you done yet?" until eventually the server says, "Yes, here's something to display on the page".
Fortunately, you don't need to start from scratch. Here you'll find an example by Microsoft that does all of this; you can modify it to suit your needs. It's also worth mentioning that in addition to being non-trivial to program, it also consumes a lot of resources to constantly poll the server, so be sure you really need to do this.
Option 2 is to just not start the other tasks in new threads, and execute the code serially before the page is ever returned to the user. They'll be staring at a blank screen for a while, but it'll be MUCH easier to program. The one downsize to keep an eye on here is on timeouts if the task is REALLY long running.

Java equivalent of C# Action.BeginInvoke

I have this C# code:
Action action = MyFunction;
action.BeginInvoke(action.EndInvoke, action);
which, from what I can tell, just runs MyFunction asynchronously. Can you do the same thing in Java?
This is how you could run an action in its own thread in Java:
new Thread(new Runnable() {
#Override
public void run() {
aFunctionThatRunsAsynchronously();
}
}).start();
There are other higher-level frameworks available that give you more control on how things are run such as Executors, which can for example be used to schedule events.
Natively, the ExecutorService provides the closest I can think of. Here's how you can use the ExecutorService to run a method async and then get the return value later:
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
Future<String> future = executor.submit(new Callable<String>() {
return getSomeLongRunningSomethingHere();
});
//... do other stuff here
String rtnValue = future.get(); //get blocks until the original finishes running
System.out.println(rtnValue);
This is somewhat related to Asynchronous Event Dispatch in Java. Basically, you can structure the method you want to run as a class implementing Callable or Runnable. Java doesn't have the ability to refer to a "method group" as a variable or parameter, like C# does, so even event handlers in Java are classes implementing an interface defining the listener.
Try something like this:
Executor scheduler = Executors.newSingleThreadExecutor();
//You'd have to change MyFunction to be a class implementing Callable or Runnable
scheduler.submit(MyFunction);
More reading from the Oracle Java docs:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Executors.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ScheduledExecutorService.html

know when a new thread was created in the AppDomain your application is running after?

I would like to know if there is any way to get an event (or something else) that tells you when a new thread was created on your appdomain (C# application)? The basic idea is that when a new thread is created I need to "initialize" the thread with some settings.
I do not want to go all over my code and do that, as I don't know what future will hold.
Create a thread static variable, and initialize anything you need in the constructor.
class ThreadEnvironmentSettings
{
[ThreadStatic]
public static readonly ThreadEnvironmentSettings Settings =
new ThreadEnvironmentSettings();
public ThreadEnvironmentSettings()
{
SetupJavaEnvironment();
}
public void EnsureSetup(){
// Doesn't do anything but required to 'touch' the thread variable
}
}
Then before calling any methods that require an established environment:
ThreadEnvironmentSettigns.Settings.EnsureSetup();
I assume that java loaders execute on the other process. And .NET code just specifies correct arguments for the command line - then you can use environment variables for the whole process.
Environment variables are global to the whole process (that is all threads will have access to them even newly created ones). Here's how to set a variable in C#.

Categories

Resources