C # Возвращаемое значение из функции, вызванной в потоке - PullRequest
0 голосов
/ 03 марта 2011

У меня есть функция вычисляющего потока, которая вызывает функцию сообщения из другого потока, используя Invoke, и я хочу, чтобы этот вычислительный поток получал значение (типа value, например целое число) из этой функции сообщения. Как я могу это сделать?

Проблема в том, что я все еще получаю старое значение переменной x после Invoke (...) и ожидаю значение 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;
}

Я попробовал несколько подходов, таких как использование объекта [], объекта в качестве параметров, но безуспешно. Я думаю, что в этом случае должны происходить операции по упаковке / распаковке, но это не так. Должен ли я использовать вспомогательный тип, как это делается в режиме событий .NET, и создать объект-посредник, как владелец класса { public int x; }

Ответы [ 4 ]

4 голосов
/ 03 марта 2011
int x = 5;
object [] parms = new object []{x};

То, что делает приведенный выше код, объявляет локальную переменную, присваивает ей значение 5, затем создает массив object[], содержащий один элемент, который является копией этой локальной переменной.

Затем вы передаете этот массив в ваш Invoke вызов.

Я думаю, вы обнаружите, что после вызова Invoke, parms[0] равно 15. Но это не влияет на x, который фактически должен был бы быть передан как параметр ref для любой метод, чтобы иметь возможность изменять его локальное значение.


То, что я видел, было сделано примерно так:

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

Тогда вы можете сделать:

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;
}
1 голос
/ 03 марта 2011

Вы говорите о Control.Invoke из Windows Forms?Если да, метод также может вернуть результат, поэтому вы можете написать:

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;
}

Ваш код, вероятно, не работал, потому что вы обращались к x вместо того, чтобы выбрать новое значение из массива (это должно быть изменено).Однако использование перегрузки, которая возвращает новое значение, должно быть намного более ясным решением.

0 голосов
/ 05 марта 2011

Возможно, лучший ответ на ваш вопрос - в .NET 4.0 System.Threading.Tasks

Здесь основной поток блокируется до тех пор, пока Result не будет возвращен методом, вызванным другимнить.Если результат уже возвращен основным потоком, достигнет WriteLine, блокировка отсутствует.

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

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

ИЛИ

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

Проверьте этот блог на наличие более интересных примеров.

0 голосов
/ 03 марта 2011

Просто верните значение из метода

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;
}
...