I have the following method, which I want to run using WaitCallBack delegate (C# Thread-Pooling) technique:
public void ExportData(string data){
//Codes goes in here
}
how to use ThreadPool.QueueUserWorkItem(new WaitCallback(ExportData),object}
in order to call this method??
The WaitCallback that this function expects takes an object state parameter. So you could do this:
string data = "some data";
ThreadPool.QueueUserWorkItem(state => ExportData((string)state), data);
or update the signature of your method:
public void ExportData(object state)
{
string data = (string)state;
//Codes goes in here
}
and then:
string data = "some data";
ThreadPool.QueueUserWorkItem(ExportData, data);
Some options:
Declare the method with type string and cast
Use a lambda expression instead, e.g.
ThreadPool.QueueUserWorkItem(ignored => ExportData(value))
where I assume value is a string variable in scope at the time. This will create a new delegate instance each time you go through this code, to capture value.
A combination of the above:
ThreadPool.QueueUserWorkItem(x => ExportData((string) x), value)
This will (potentially) reuse the same delegate instance on every call, as the value is passed via the normal WaitCallback instead of being captured by the delegate.
Additionally, you might want to consider using the rather more modern Task API unless you're targeting an old version of .NET. It's a generally more pleasant way of scheduling and managing tasks.
Related
I have the method that takes an argument from external dll through a delegate pointer:
public delegate void NotificationsCallbackDelegate(CinectorNotification message);
NotificationsCallbackDelegate notificationsCallbackDeleg;
IntPtr notificationsCallbackPointer;
notificationsCallbackDeleg = NotificationsCallback;
notificationsCallbackPointer = Marshal.GetFunctionPointerForDelegate(notificationsCallbackDeleg);
instance.SetNotificationsCallback(notificationsCallbackPointer);
private void NotificationsCallback(CinectorNotification notif)
{
Log.AppendText("[" + notif.timestamp + "] " + notif.type + ": " + notif.message + Environment.NewLine);
}
So, input argument 'message' is something that can be passed by dll at any time during the application flow, whenever the external engine generates some log. It is like an event.
I use the following code to put a method on a new thread:
private void startNotifications()
{
Thread NotificationsThread = new Thread(new ThreadStart(NotificationsCallback));
NotificationsThread.IsBackground = true;
NotificationsThread.Start();
}
However, the method NotificationsCallback(CinectorNotification notif) takes in an argument and therefore doesn't match the delegate for ThreadStart. So how would I put a method like this on a different thread?
You can use Task.Run and supply it a lambda where you call NotificationsCallback with whatever arguments you need For example:
private void startNotifications()
{
Task.Run(() => NotificationsCallback(arg1, arg2) );
}
This will result in NotificationsCallback being run on on a ThreadPool thread.
For more information on Task.Run, see: https://msdn.microsoft.com/en-us/library/hh195051(v=vs.110).aspx
You code would work if there is a method passed in the parameter is parameterless.
If you want a parametrised thread, you should use another overload of the Thread constructor which will take ParameterizedThreadStart.
Start method on the thread is then called with an argument which is passed on to the thread method like this:
Thread thread = new Thread(WorkerMethod);
thread.Start(35); //for example 35
void WorkerMethod(object parameter)
{
int? intParameter = parameter as int?; //for example
if (intParameter.HasValue)
{
//do stuff
}
}
You can also use Task, which is a more modern approach to multi-threading.
Task.Factory.StartNew(() => WorkerMethod(35)); //for example 35
Or Task.Run in .NET 4.5 and newer. In task one can pass as many paramaters as wanted (without creating a container for them) and also the parameters can be strongly typed... not just object.
Instead of using ThreadStart you could use ParameterizedThreadStart and pass the required parameters in Thread.Start.
I follow Passing Data to a Thread of "PART 1: GETTING STARTED" of "Threading in C#" by Joseph Albahari.
Namely the passage:
====== Start of quote
"With this approach, you can pass in (to where?) any number of arguments to the method. You can even wrap the entire implementation in a multi-statement lambda:
new Thread (() =>
{
Console.WriteLine ("I'm running on another thread!");
Console.WriteLine ("This is so easy!");
}).Start();*
You can do the same thing almost as easily in C# 2.0 with anonymous methods:
new Thread (delegate()
{
...
}).Start();
============ End of quote
That is, I've tried the "easily" as:
new Thread
(delegate
{
Console.WriteLine("I'm running on another thread!");
Console.WriteLine("This is so easy!");
}
).Start();
but it produces the error:
The call is ambiguous between the following methods or properties:
'System.Threading.Thread.Thread(System.Threading.ThreadStart)' and
'System.Threading.Thread.Thread(System.Threading.ParameterizedThreadStart)'
How can you disambiguate the code in order to run it? Answered (missed parenthesis. Anyway, it wasn't the original main question)
Also, I did not quite grasp where is the empty list () => directed/applied to?
A well as, what is the method to which " you can pass in any number of arguments to the method"?
How to understand the passing of (any number of) arguments through the empty list?
Update (addressing Jon Skeet's comment):
No, I am not stuck with C# 2.
The same question(s) to the previous passage:
========== Start of quote:
"The easiest way to pass arguments to a thread’s target method is to execute a lambda expression that calls the method with the desired arguments:
static void Main()
{
Thread t = new Thread ( () => Print ("Hello from t!") );
t.Start();
}
static void Print (string message)
{
Console.WriteLine (message);
}
With this approach, you can pass in any number of arguments to the method."
=============== End of quote
Update2:
The most complete answer is IMO by #Lee though I marked as correct another answer for guessing to answer at once what I have not even originally asked - how to put something in empty parenthesis (I'm already afraid to call it by list or by arguments)
You need to make the argument list explicit:
new Thread
(delegate()
{
Console.WriteLine("I'm running on another thread!");
Console.WriteLine("This is so easy!");
}
).Start();
The delegate keyword allows you to define an anonymous method. Lambda expressions (i.e. using the () => { ... } syntax) are similar, however using delegate allows you to omit the parameter list. This is ambiguous in this case, since there are two constructors for Thread which take different delegate types. One takes a ThreadStart which is defined as
delegate void ThreadStart();
and the other takes a ParameterizedThreadStart which is defined as:
delegate void ParameterizedThreadStart(object state);
Since you are omitting the parameter list, the compiler does not know which delegate type you are using.
I assume the "any number of arguments" are variables which are closed-over by your delegate. For example you could have:
string message = "This is so easy!";
var thread = new Thread(delegate() {
Console.WriteLine(message);
});
thread.Start();
You can use a ParameterizedThreadStart to pass an arbitrary object to your thread delegate e.g.
public class ThreadData {
//properties to pass to thread
}
ThreadData data = new ThreadData { ... }
Thread thread = new Thread((object state) => {
ThreadData data = (ThreadData)state;
});
thread.Start(data);
You need the parentheses after delegate to specify the parameters, in this case no parameters:
new Thread(
delegate() {
Console.WriteLine("I'm running on another thread!");
Console.WriteLine("This is so easy!");
}
).Start();
The "any number of arguments" that the author is talking about is that you can use data from the scope where the delegate is created inside the code that runs in a separate thread, without having to pass the data to the Start method:
string msg1 = "I'm running on another thread!";
string msg2 = "This is so easy!";
new Thread(
delegate() {
Console.WriteLine(msg1);
Console.WriteLine(msg2);
}
).Start();
What's actually happening is that the variables are no longer local variables in the method, instead they are automatically stored in a closure, which the delegate shares with the method where it is defined.
This works well as long as you only want to start one thread. If you want to start multiple threads that uses different data, you would either pass the data into the Start method or create a class that can hold the data, put the code for the thread in the class, and create one instance for each thread that you start.
In order to resolve ambiguous call, you can add empty parentheses (delegate will be treated as ThreadStart delegate):
new Thread(delegate() {
Console.WriteLine("I'm running on another thread!");
Console.WriteLine("This is so easy!");
}).Start();
Or add state parameter (delegate will be treated as ParametrizedThreadStart) It works, but it's odd, because you don't need that parameter.
new Thread(delegate(object state) {
Console.WriteLine("I'm running on another thread!");
Console.WriteLine("This is so easy!");
}).Start();
Or cast delegate to ThreadStart
new Thread((ThreadStart)delegate {
Console.WriteLine("I'm running on another thread!");
Console.WriteLine("This is so easy!");
}).Start();
() => isn't an empty list in C#. In the context it is used in the book it is the start of a lambda expression. The () means that this expression takes no arguments.
How can I pass a Method2 to thread as shown in below if i write code as shown in below it shows an error Error
The best overloaded method match for
'System.Threading.Thread.Thread(System.Threading.ThreadStart)' has
some invalid arguments
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main Thread : ");
Thread obj = new Thread(Method2);
obj.Start();
Console.ReadLine();
}
private static int Method2(int a)
{
return a;
}
}
When i use the following code it works
Thread obj = new Thread(() => Method2(1));
But why it's not working when i pass delegate object
delegate int del(int i);
del d = Method2;
Thread obj = new Thread(d);
What is the difference between above 2 , in 1st case i used Lambda expression in second case directly passed delegate object is there any thing else?
The Thread constuctor takes two types of delegates, ThreadStart and ParameterizedThreadStart. To see what type of method these delegates accept you can create it and the constructor will show you, so for example,
var parameterMethod = new ParameterizedThreadStart(...
If you type the above you will see the delegate takes a function with one object as the parameter and returns void.
void (object) target
This is why your Method that takes an int will not work because the signature does not match the delegate target signature. When you wrap it in a lambada, you are actually passing in a method that takes no parameters and returns void, so the Method2 signature is not even looked at. Wrapping method calls with a lambada like this can be very useful for getting the signature to match.
delegate void del(object obj);
del d = () => Method2(1);
Thread obj = new Thread(d);
There is an infinite number of possible method signatures so Threads and Tasks keep it simple and say if you want to pass something, pass a single object. Since all types derive from object, this lets you pass in anything you want, then cast it later.
Try this:
Thread obj = new Thread(() => Method2(some_int_value));
I am having a problem with setting referenced variable inside of thread.
Error:"Cannot use ref or out parameter 'output' inside an
anonymous method, lambda expression, or query expression"
Is there any way to get this to work or achieve similar effect?
public static void LoadThreaded<T>(string path, ref T output)
{
ThreadStart threadStart = delegate
{
output = Loader<T>(path);
};
new Thread(threadStart).Start();
}
The problem is that the method returns prior to the output variable being set (necessarily), as the output is set by a different thread.
The best option here would be to use the TPL to rework this, ie:
Task<T> LoadThreaded<T>(string path)
{
return Task.Factory.StartNew( () => Loader<T>(path) );
}
This allows you to start this asynchronous operation, and get the result when it completes, either by blocking (calling output.Result) or by adding a task continuation.
I've been trying to pass an object to my main thread process but it seems it will not work in the way I thought it would.
First I create the Thread:
Thread thrUDP;
Then I create the object I will use to store the data I need:
UDPData udpData;
Now I Initialize the object withthe correct data, Set up the new thread and start it with the object passed into the Start() method:
udpData = new UDPData("224.5.6.7", "5000", "0", "2");
thrUDP = new Thread(new ParameterizedThreadStart(SendStatus));
thrUDP.Start(udpData);
This is the method I wish to start:
private void SendStatus(UDPData data)
{
}
I remember using Threads a while back and I'm sure they weren't so difficult to pass data to, am I doing this the wrong way or am I just missing a piece of code?
Thanks!
The ParameterizedThreadStart delegate is declared as:
public delegate void ParameterizedThreadStart(object obj);
Clearly, this delegate isn't compatible with your method's signature, and there isn't a direct way to get a System.Threading.Thread to work with an arbitrary delegate-type.
One of your options would be to use a compatible signature for the method, and cast as appropriate:
private void SendStatus(object obj)
{
UDPData data = (UDPData)obj;
...
}
The other option would be to punt the problem to the C# compiler, creating a closure. For example:
new Thread(() => SendStatus(udpData)).Start();
Do note that this uses the ThreadStart delegate instead. Additionally, you should be careful with subsequently modifying the udpData local, since it is captured.
Alternatively, if you don't mind using the thread-pool instead of spawning your own thread, you could use asynchronous delegates. For example:
Action<UDPData> action = SendStatus;
action.BeginInvoke(udpData, action.EndInvoke, null);
private void SendStatus(object data)
{
UDPData myData = (UDPData) data;
}