ThreadPool.QueueUserWorkItem with function argument - c#

I am using C# 2.0 and want to call a method with a couple of parameters with the help of ThreadPool.QueueUserWorkItem, so I tried as follows:
ThreadPool.QueueUserWorkItem(new WaitCallback(Multiply(2, 3)));
private int Multiply(int x,int y)
{
int z=(x*y);
return z;
}
I am getting compilation error. So please guide me, how can I call a function with multiple arguments with ThreadPool.QueueUserWorkItem?.
I have another query that when I am using ThreadPool.QueueUserWorkItem then how to use here anonymous function as a result I can write the code there instead of calling another function. If it is possible in C# v2.0 then please guide me with code.

You should declare a method which have the same definition as WaitCallback delegate. You can use the following code snippet:
ThreadPool.QueueUserWorkItem(Multiply, new object[] { 2, 3 });
public static void Multiply(object state)
{
object[] array = state as object[];
int x = Convert.ToInt32(array[0]);
int y = Convert.ToInt32(array[1]);
}
Anonymous delegate version is:
ThreadPool.QueueUserWorkItem(delegate(object state)
{
object[] array = state as object[];
int x = Convert.ToInt32(array[0]);
int y = Convert.ToInt32(array[1]);
}
, new object[] { 2, 3 });

Using a lambda expression would also work
ThreadPool.QueueUserWorkItem(state => Multiply(2,3));

Here's a fuller example which gets the result back to the initial thread, and shows how the delegate can be defined anonymously:
class Program
{
static void Main(string[] args)
{
using (MultiplyTask task = new MultiplyTask() { Multiplicands = new int[] { 2, 3 } })
{
WaitCallback cb = new WaitCallback(delegate(object x)
{
MultiplyTask theTask = x as MultiplyTask;
theTask.Result = theTask.Multiplicands[0] * theTask.Multiplicands[1];
theTask.Set();
});
ThreadPool.QueueUserWorkItem(cb, task);
Console.WriteLine("Calculating...");
if (task.WaitOne(1000))
{
Console.WriteLine("{0} times {1} equals {2}", task.Multiplicands[0], task.Multiplicands[1], task.Result);
}
else
{
Console.WriteLine("Timed out waiting for multiplication task to finish");
}
}
}
private class MultiplyTask : EventWaitHandle
{
internal MultiplyTask() : base(false, EventResetMode.ManualReset) { }
public int[] Multiplicands;
public int Result;
}
}

In my case, I needed an anonymous function. i.e., write to a stream asynchronously. So I used this:
ThreadPool.QueueUserWorkItem(state => {
serializer.Serialize(this.stream);
this.stream.Flush();
});

for passing arguments without lambda - just pack all arguments into a class/object
MyArgumentsClass m_MyArgumentsClass = new MyArgumentsClass();
//fill arguments in class
ThreadPool.QueueUserWorkItem(new WaitCallback(MyFunction), m_MyArgumentsClass);
then, in the function - cast the object into your arguments class
public void MyFunction(object msg)
{
MyArgumentsClass m_MyArgumentsClass = (MyArgumentsClass)msg;

Related

C# Pass Class as parameter to method and call static method in there

I am new to C# and looking the best way to do the following implementation.
My project got several Model classes (like 25) and each class got a static method called "process()", which just takes a bit of time to finish it's task.
I need to call all these method in each class one after another and to add some logs (write status of method execution in to file) to track execution.
I can simply do the following, But surely there should be a better professional way to do this
Log.WriteLog(DateTime.Now + " Class A Process Started");
ClassA.Process()
Log.WriteLog(DateTime.Now + " Class A Process Finished");
Log.WriteLog(DateTime.Now + " Class B Process Started");
ClassB.Process()
Log.WriteLog(DateTime.Now + " Class B Process Finished");
............ continue 25 classes
What I am trying to do is to write a method and just Add Logs and repetitive work in there..
private void CommonMethod(Class)
{
Check what class
Add Process started Log
Call Process method
Add proicess finished Log
}
You could create function that takes a delegate and performs the logging, something like this:
public void ProcessAndLog(Action action, String processName)
{
Log.WriteLog(DateTime.Now + $" Class {processName} Process Started");
action();
Log.WriteLog(DateTime.Now + $" Class {processName} Process Finished");
}
and call it like so:
ProcessAndLog(ClassA.Process, "A"); //"A" could be part of ClassA - e.g. ClassA.Name;
ProcessAndLog(ClassB.Process, "B");
//etc
This will work so long as every Process method has no params and retuns void - the signature of the Action delegate.
If it has parameters, you can call it like so:
ProcessAndLog(() => ClassC.Process("value"), "C");
If you need a return value, consider a Func<T> instead of Action.
You can do this:
private void CommonMethod<T>()
{
//Add Process started Log
//Call Process method
typeof(T).GetMethod("process")?.Invoke(null, null); // not target needed
//Add proicess finished Log
}
Usage:
CommonMethod<ClassA>();
CommonMethod<ClassB>();
Static interfaces don't exist in C#. The only way to reference a static member of a class is by its class name and member name.
An alternative would be to use reflection. Get the static method by it's string name and invoke it. Like this:
static void CommonMethod(Type type)
{
MethodInfo methodInfo = type.GetMethod("TheStaticMethodName");
if (methodInfo != null)
{
methodInfo.Invoke(null, new object[0]);
}
}
//Invoke it like this
CommonMethod(typeof(MyStaticType));
The first parameter for Invoke is the target. For an instance method you would pass a class instance you want to invoke on, but for static members just put null.
The second parameter is the arguments. You can put an empty array the if there's no arguments.
Also, you could have the same method with a generic type like this:
static void CommonMethod<T>()
{
MethodInfo methodInfo = typeof(T).GetMethod("TheStaticMethodName");
if (methodInfo != null)
{
methodInfo.Invoke(null, new object[0]);
}
}
Note that generics aren't always the best since they generate a lot of stuff at compile time.
Here's another suggestion:
class Program
{
static void Main(string[] args)
{
var x = new Calculate { a = 1, b = 2 };
var y = new Calculate { a = 10, b = 20 };
var z = new Calculate { a = 100, b = 200 };
var calculations = new List<Calculate>{
new Calculate() { a = 1, b = 2 },
new Calculate() { a = 10, b = 20 },
new Calculate() { a = 100, b = 200 }
};
calculations.ForEach(c =>
{
c.Process();
});
}
}
class Calculate
{
public int a { get; set; }
public int b { get; set; }
public void Process()
{
Console.WriteLine(a + b);
}
}

Pass delegate together with parameter to a function

I want enqueue a list of tasks and then perform on certain event. Code:
internal class MyClass
{
private Queue<Task> m_taskQueue;
protected MyClass()
{
m_taskQueue = new Queue<Task>();
}
public delegate bool Task(object[] args);
public void EnqueueTask(Task task)
{
m_taskQueue.Enqueue(task);
}
public virtual bool Save()
{
// save by processing work queue
while (m_taskQueue.Count > 0)
{
var task = m_taskQueue.Dequeue();
var workItemResult = task.Invoke();
if (!workItemResult)
{
// give up on a failure
m_taskQueue.Clear();
return false;
}
}
return true;
}
}
Each delegate task may have their own list of parameters: Task(object[] args). My question is how to pass the parameter to each task for the task queue?
Okay, now we have a bit more information, it sounds like your EnqueueTask method should actually look like this:
public void EnqueueTask(Task task, object[] values)
Right?
For starters I would avoid using the name Task, which is already part of the core of .NET 4 and will become very prominent in .NET 5. As Joshua said, you've basically got a Func<object[], bool>.
Next, you could keep two lists - one for the delegates and one for the values, but it's easier just to keep a Queue<Func<bool>> like this:
private readonly Queue<Func<bool>> taskQueue = new Queue<Func<bool>>();
public void EnqueueTask(Task task, object[] values)
{
taskQueue.Enqueue(() => task(values));
}
Then the rest of your code will actually work "as is". The lambda expression there will capture values and task, so when you invoke the Func<bool>, it will supply those values to the original delegate.
Provided understanding your question correctly you just pass the information like a normal call. Have you considered using Func? You can just pass arguments to the Task.Invoke i.e. Task.Invoke([arguments here as a *single* object array]).
object[] arguments = null; // assign arguments to something
var workItemResult = task.Invoke(arguments);
Below is an example with the Func type.
internal class MyClass
{
private Queue<Func<object[], bool>> m_taskQueue;
protected MyClass()
{
m_taskQueue = new Queue<Func<object[], bool>>();
}
public void EnqueueTask(Func<object[], bool> task)
{
m_taskQueue.Enqueue(task);
}
public virtual bool Save()
{
object[] arguments = null; // assign arguments to something
// save by processing work queue
while (m_taskQueue.Count > 0)
{
var task = m_taskQueue.Dequeue();
var workItemResult = task(arguments);
if (!workItemResult)
{
// give up on a failure
m_taskQueue.Clear();
return false;
}
}
return true;
}
}

C# method name expected

I just trying to pass some values but it's throwing an error all the time. Can some one correct me what I am missing here?
Am getting error here
Thread t_PerthOut = new Thread(new ThreadStart(ReadCentralOutQueue("test"));
I want to pass this string value to ReadCentralOutQueue.
class Program
{
public void Main(string[] args)
{
Thread t_PerthOut = new Thread(new ThreadStart(ReadCentralOutQueue("test"));
t_PerthOut.Start();
}
public void ReadCentralOutQueue(string strQueueName)
{
System.Messaging.MessageQueue mq;
System.Messaging.Message mes;
string m;
while (true)
{
try
{
}
else
{
Console.WriteLine("Waiting for " + strQueueName + " Queue.....");
}
}
}
catch
{
m = "Exception Occured.";
Console.WriteLine(m);
}
finally
{
//Console.ReadLine();
}
}
}
}
This code:
Thread t_PerthOut = new Thread(new ThreadStart(ReadCentralOutQueue("test"));
tries to call ReadCentralOutQueue and then create a delegate from the result. That isn't going to work, because it's a void method. Normally you'd use a method group to create a delegate, or an anonymous function such as a lambda expression. In this case a lambda expression will be easiest:
Thread t_PerthOut = new Thread(() => ReadCentralOutQueue("test"));
You can't just use new Thread(ReadCentralOutQueue) as the ReadCentralOutQueue doesn't match the signature for either ThreadStart or ParameterizedThreadStart.
It's important that you understand why you're getting this error, as well as how to fix it.
EDIT: Just to prove it does work, here's a short but complete program:
using System;
using System.Threading;
class Program
{
public static void Main(string[] args)
{
Thread thread = new Thread(() => ReadCentralOutQueue("test"));
thread.Start();
thread.Join();
}
public static void ReadCentralOutQueue(string queueName)
{
Console.WriteLine("I would read queue {0} here", queueName);
}
}
You have to do it like this:
var thread = new Thread(ReadCentralOutQueue);
thread.Start("test");
Also ParameterizedThreadStart expects a delegate which takes an object as parameter so you need to change your signature to this:
public static void ReadCentralOutQueue(object state)
{
var queueName = state as string;
...
}
Parameters are not allowed as part of the ThreadStart delegate. There are several other solutions to passing a parameter to a new thread, discussed here: http://www.yoda.arachsys.com/csharp/threads/parameters.shtml
But the one that would probably be simplest in your case is the anonymous method:
ThreadStart starter = delegate { Fetch (myUrl); };
new Thread(starter).Start();

Using delegates with arguments

I have a class 'KeyEvent'; one of which's members is:
public delegate void eventmethod(object[] args);
And the method passed to the object in the constructor is stored in this member:
private eventmethod em;
Constructor:
public KeyEvent(eventmethod D) {
em = D;
}
public KeyEvent(eventmethod D, object[] args) : this(D) {
this.args = args;
}
public KeyEvent(Keys[] keys, eventmethod D, object[] args) : this(keys, D) {
this.args = args;
}
The 'eventmethod' method is then called by using the public method "ThrowEvent":
public void ThrowEvent() {
if (!repeat && thrown) return;
em.DynamicInvoke(args);
this.thrown = true;
}
As far as I can see, this compiles fine. But when trying to create an instance of this class (KeyEvent), I'm doing something wrong. This is what I have so far:
object[] args = {new Vector2(0.0f, -200.0f)};
Keys[] keys = { Keys.W };
KeyEvent KeyEvent_W = new KeyEvent(keys, new KeyEvent.eventmethod(GameBase.ChangeSquareSpeed), args);
GameBase.ChangeSquareSpeed doesn't do anything at the moment, but looks like this:
static public void ChangeSquareSpeed(Vector2 squarespeed) {
}
Anyway, the erroneous line is this one:
KeyEvent KeyEvent_W = new KeyEvent(keys, new KeyEvent.eventmethod(GameBase.ChangeSquareSpeed), args);
The error that the compiler gives me is:
error CS0123: No overload for 'ChangeSquareSpeed' matches delegate 'BLBGameBase.KeyEvent.eventmethod'
My question is: Does this mean I have to change ChangeSquareSpeed to take no parameters (in which case, what is a better way of doing this?), or am I doing something syntactically wrong?
Thank you in advance.
I think the error is very explicit. Your ChangeSquareSpeed method doesn't match the delegate . The delegate expects a method with one object[] as parameter but your passing a method with a Vector2 as a parameter, hence the error.
Try this method:
static public void ChangeSquareSpeed(object[] squarespeed)
{}
(update)
I see some confusion in your code, specially in the line:
object[] args = {new Vector2(0.0f, -200.0f)};
I can't really understand if you want an array of Vector2's or just a Vector2's object.
If you pretend to have an array of Vector2's I think this might seem reasonable:
Change the delegate to:
public delegate void eventmethod(Vector2 args);
and then
public void ThrowEvent() {
if (!repeat && thrown) return;
foreach(object obj : args)
{
em.DynamicInvoke((Vector2)obj);
}
this.thrown = true;
}
(update 2)
In that case, I think you should create a generic version of KeyEvent. See this example and go from there:
class KeyEvent<T>
{
public T Args { get; set; }
public Action<T> A { get; set; }
public KeyEvent() { }
public void ThrowEvent()
{
A.DynamicInvoke(Args);
}
}
// ...
static void M1(object[] o)
{
Console.WriteLine("M1 {0}", o);
}
static void M2(Vector2 v)
{
Console.WriteLine("M2 {0}", v);
}
static void Main(string[] args)
{
KeyEvent<object[]> e1 = new KeyEvent<object[]>
{
A = new Action<object[]>(M1),
Args = new object[] {};
};
KeyEvent<Vector2> e2 = new KeyEvent<Vector2>
{
A = new Action<Vector2>(M2),
Args = new Vector2();
};
}
The delegate eventmethod states that all events using it should take object[] (args) as their only in parameter. Depending on what you're using this code for, you want to either:
Change the signature of ChangeSquareSpeed to ChangeSquareSpeed(object[] squarespeed)
Create a new delegate, with the signature void neweventmethod(Vector2 args); and use that
Change the signature of eventmethod to the above
If you are on C# 3, change the delegate to an Action<object[]>. That will make your life much simpler, as it will be type-safe to invoke it.
That would allow you to simply invoke it like this:
this.em(args);
and you would have compile-time checking instead.

Anonymous method as parameter to BeginInvoke?

Why can't you pass an anonymous method as a parameter to the BeginInvoke method? I have the following code:
private delegate void CfgMnMnuDlg(DIServer svr);
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke((CfgMnMnuDlg)ConfigureMainMenu,
new object[] { server});
}
else
{
// Do actual work here
}
}
I'm trying to avoid declaring the delegate. Why can't I write something like the below instead? Or can I, and I just can't figure out the correct syntax? The below currently generates an:
Argument type 'Anonymous method' is not assignable to parameter type 'System.Delegate'
Ok, that's right of course, but is there some other syntax I can use to do this (avoid having to declare a separate delegate in order to use BeginInvoke()?
(Being able to do this would fit in neatly with the concept of using anon methods/lamdas in place of explicit delegates which works so cleanly everywhere else.)
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke( // pass anonymous method instead ?
delegate(DIServer svr) { ConfigureMainMenu(server);},
new object[] { server});
}
else
{
// Do actual work here
}
}
Try this:
control.BeginInvoke((MethodInvoker) delegate { /* method details */ });
Or:
private void ConfigureMainMenu(DIServer server)
{
if (control.InvokeRequired)
{
control.BeginInvoke(new Action<DIServer >(ConfigureMainMenu), server);
}
else
{
/* do work */
}
}
Or:
private void ConfigureMainMenu(DIServer server)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
// Private variable
_methodInvoker = new MethodInvoker((Action)(() => ConfigureMainMenu(server)));
_methodInvoker.BeginInvoke(new AsyncCallback(ProcessEnded), null); // Call _methodInvoker.EndInvoke in ProcessEnded
}
else
{
/* do work */
}
}
You should be able to write something like this:
private void ConfigureMainMenu(DIServer server,)
{
MenuStrip mnMnu = PresenterView.MainMenu;
if (mnMnu.InvokeRequired)
{
mnMnu.BeginInvoke(new Action<DIServer>(ConfigureMainMenu),
new object[] { server});
}
else
{
// Do actual work here
}
}
You could write an extension method that would wrap anonymous methods, and even take care of the InvokeRequired semantics:
public static void InvokeAction(this Control ctl, Action a)
{
if (!ctl.InvokeRequired)
{
a();
}
else
{
ctl.BeginInvoke(new MethodInvoker(a));
}
}
This would allow you to do:
control.InvokeAction(delegate() { ConfigureMainMenu(server); });
You can do this in a single method by calling invoking yourself:
ClassData updData = new ClassData();
this.BeginInvoke(new Action<ClassData>(FillCurve),
new object[] { updData });
...
public void FillCurve(ClassData updData)
{
...
}
For completely anonymous methods with a limited number of parameters:
Func<int, int?> caller = new Func<int, int?>((int param1) =>
{
return null;
});
caller.BeginInvoke(7, new AsyncCallback((IAsyncResult ar) =>
{
AsyncResult result = (AsyncResult)ar;
Func<int, int?> action = (Func<int, int?>)result.AsyncDelegate;
action.EndInvoke(ar);
}), null);
You can use one of the other Func delegate types as needed.
I've tried a bunch of different methods but none work. ie...
// Fails -- cannot convert lamda to System.Delegate
mnMnu.BeginInvoke( (DIServer svr)=> {ConfigureMainMenu(server);}, new object[] server);
// Fails -- cannot convert anonymous method to System.Delegate
mnMnu.BeginInvoke( new delegate(DIServer svr){ConfigureMainMenu(server);}, new object[] server);
So, the short answer is no. You could create short helper delegates in the given context and use lambdas to make it a bit neater but that's pretty much it.
EDIT: Turns out I'm wrong. The methodinvoker answer below works.
See this page

Categories

Resources