0

I have a calculating thread function which invokes message function from other thread using Invoke and I want that calculating thread to get value(of valuetype, like integer) from that message function. How can I do this?

The problem is that I still get old value of x variable after Invoke(...) and I expect value of 15

delegate void mes_del(object param);

void MyThreadFunc()
{
...
int x = 5;
object [] parms = new object []{x};
Invoke(new mes_del(MessageFunc), (object)parms);
...
}

void MessageFunc(object result)
{
   int res = 15;
   (result as object[])[0] = res;
}

I tried some approaches like using object[], object as parameters with no success. I though boxing/unboxing operations should occur in such a case but they don't. Should I use auxiliary type like it is done in .NET event mode and create mediator object like class holder { public int x; }

Blablablaster
  • 3,238
  • 3
  • 31
  • 33
  • Give us a little more code. What comes after you call `Invoke` in your code? The `MessageFunc` is correctly changing the value, so either you're not waiting for the asynchronous task to complete, or your code to get the modified value is incorrect. – Jim Mischel Mar 03 '11 at 15:43
  • @Jim: It isn't changing the value of `x`! – Dan Tao Mar 03 '11 at 16:09
  • @Dan Tao: Of course it isn't changing the value of `x`! – Jim Mischel Mar 03 '11 at 19:35
  • 2
    @Jim: The OP said, "The problem is that I still get **old value of x** variable after Invoke(...)"; your comment made it sound like you were suggesting the problem had to do with waiting on an async call when in fact the OP's current code would *never* change the value of `x`. Also, assuming the OP is using Windows Forms, `Control.Invoke` automatically waits for the UI to execute the code (as opposed to `Control.BeginInvoke`, which doesn't). – Dan Tao Mar 03 '11 at 20:12
  • @Dan Tao: I guess I gave more credit than was due. I didn't consider that the OP was expecting `x` to change automatically. I figured he knew that he had to get the new value of `x` from the array. And, yes, I somehow read `Invoke` as `BeginInvoke`. – Jim Mischel Mar 03 '11 at 23:17
  • The question probably should be whether you should use invoke (run this on another thread or not) by looking at your expectation it looks like you want MessegeFunc to return before you continue further, so ideally you shuould just call it synchronously (on the same thread). – Sanjeevakumar Hiremath Mar 04 '11 at 23:16

4 Answers4

4
int x = 5;
object [] parms = new object []{x};

What the above code does is declare a local variable, assign it the value 5, then construct an object[] array containing one element which is a copy of that local variable.

You then pass this array into your Invoke call.

I think what you'll find is that after Invoke is called, parms[0] is 15. But this does not affect x, which would actually have to be passed as a ref parameter for any method to be able to modify its local value.


What I've seen done before is something like this:

class Box<T>
{
    public T Value { get; set; }
}

Then you could do:

void MyThreadFunc()
{
    var x = new Box<int> { Value = 5 };

    // By the way, there's really no reason to define your own
    // mes_del delegate type.
    Invoke(new Action<Box<int>>(MessageFunc), x);
}

void MessageFunc(Box<int> arg)
{
    arg.Value = 15;
}
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • Just Fyi: [`StrongBox`](http://msdn.microsoft.com/en-us/library/bb549038.aspx) class – Ani Mar 03 '11 at 15:52
  • @Ani: Yeah, I actually noticed that before. But this makes me nervous: "This API supports the .NET Framework infrastructure and is not intended to be used directly from your code." Almost sounds like they reserve the right to just get rid of that class. (Plus, it's in a pretty obscure namespace.) – Dan Tao Mar 03 '11 at 15:56
1

Are you talking about Control.Invoke from Windows Forms? If yes, the method can also return a result, so you can write:

delegate int mes_del(int param);

void MyThreadFunc() {
  int x = 5;
  object [] parms = new object []{x};
  x = (int)Invoke(new mes_del(MessageFunc), x);
  // you'll get a new value of 'x' here (incremented by 10)
}

int MessageFunc(int result) {
  return result + 10;
}

Your code probably didn't work, because you were accessing x instead of picking a new value from the array (that should be modified). However, using an overload that returns a new value should be a much clearer solution.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
0

Just return value from method

void MyThreadFunc()
{
...
int x = 5;
object [] parms = new object []{x};
var callResult = (int)Invoke((Func<object,int>)MessageFunc, (object)parms);
...
}

int MessageFunc(object result)
{
   int res = 15;
   return res;
}
Viacheslav Smityukh
  • 5,652
  • 4
  • 24
  • 42
  • Your example won't compile. The `mes_del` delegate type returns `void`, so `new mes_del(MessageFunc)` will give an error that `MessageFunc` has the wrong return type. – Harry Steinhilber Mar 04 '11 at 14:36
0

Perhaps the best answer to your question is in .NET 4.0 System.Threading.Tasks

Here the main thread is blocked till the Result is returned by the method called on the other thread. If the result is already returned by the main thread reaches the WriteLine there is no blocking.

Task task = Task.Factory.StartNew(SomeMethod);
Console.WriteLine(task.Result);

public static string SomeMethod()
{
    return "Hello World";
}

OR

Task task = Task.Factory.StartNew(() => { return "Hello World"; } );
Console.WriteLine(task.Result);

Check this blog for more interesting samples.

Sanjeevakumar Hiremath
  • 10,985
  • 3
  • 41
  • 46