Мне нравится называть метод в потоке с аргументами и возвращать некоторое значение здесь пример
class Program
{
static void Main()
{
Thread FirstThread = new Thread(new ThreadStart(Fun1));
Thread SecondThread = new Thread(new ThreadStart(Fun2));
FirstThread.Start();
SecondThread.Start();
}
public static void Fun1()
{
for (int i = 1; i <= 1000; i++)
{
Console.WriteLine("Fun1 writes:{0}", i);
}
}
public static void Fun2()
{
for (int i = 1000; i >= 6; i--)
{
Console.WriteLine("Fun2 writes:{0}", i);
}
}
}
Я знаю это выше примера, выполненного успешно, но если метод fun1 как это
public int fun1(int i,int j)
{
int k;
k=i+j;
return k;
}
затем, как я могу назвать это в потоке?
Это может быть другой подход. Здесь ввод передается как параметризованный поток, а тип возвращаемого значения передается в событии делегата, так что, когда поток завершится, он вызовет делегат. Это будет нормально, чтобы получить результат, когда поток завершится.
public class ThreadObject
{
public int i;
public int j;
public int result;
public string Name;
}
public delegate void ResultDelegate(ThreadObject threadObject);
public partial class Form1 : Form
{
public event ResultDelegate resultDelete;
public Form1()
{
InitializeComponent();
resultDelete += new ResultDelegate(resultValue);
}
void resultValue(ThreadObject threadObject)
{
MessageBox.Show("Thread Name : " + threadObject.Name + " Thread Value : " + threadObject.result);
}
private void button1_Click(object sender, EventArgs e)
{
ThreadObject firstThreadObject = new ThreadObject();
firstThreadObject.i = 0;
firstThreadObject.j = 100;
firstThreadObject.Name = "First Thread";
Thread firstThread = new Thread(Fun);
firstThread.Start(firstThreadObject);
ThreadObject secondThreadObject = new ThreadObject();
secondThreadObject.i = 0;
secondThreadObject.j = 200;
secondThreadObject.Name = "Second Thread";
Thread secondThread = new Thread(Fun);
secondThread.Start(secondThreadObject);
}
private void Fun(object parameter)
{
ThreadObject threadObject = parameter as ThreadObject;
for (; threadObject.i < threadObject.j; threadObject.i++)
{
threadObject.result += threadObject.i;
Thread.Sleep(10);
}
resultValue(threadObject);
}
}
Для некоторых альтернатив; currying:
static ThreadStart CurryForFun(int i, int j)
{ // also needs a target object if Fun1 not static
return () => Fun1(i, j);
}
Thread FirstThread = new Thread(CurryForFun(5, 12));
или напишите свой собственный тип захвата (это в целом сопоставимо с тем, что компилятор делает для вас, когда вы используете анонимные методы / лямбда-выражения с захваченными переменными, но было реализовано иначе):
class MyCaptureClass
{
private readonly int i, j;
int? result;
// only available after execution
public int Result { get { return result.Value; } }
public MyCaptureClass(int i, int j)
{
this.i = i;
this.j = j;
}
public void Invoke()
{ // will also need a target object if Fun1 isn't static
result = Fun1(i, j);
}
}
...
MyCaptureClass capture = new MyCaptureClass(5, 12);
Thread FirstThread = new Thread(capture.Invoke);
// then in the future, access capture.Result
Вы можете использовать перегрузку ParameterizedThreadStart в конструкторе Thread. Он позволяет вам передавать объект в качестве параметра методу потока. Это будет единственный параметр объекта, поэтому я обычно создаю класс параметров для таких потоков. Этот объект также может хранить результат выполнения потока, который вы можете прочитать после завершения потока.
Не забывайте, что доступ к этому объекту во время работы потока возможен, но не является «потокобезопасным». Вы знаете, что делать :)
Вот пример:
void Main()
{
var thread = new Thread(Fun);
var obj = new ThreadObject
{
i = 1,
j = 15,
};
thread.Start(obj);
thread.Join();
Console.WriteLine(obj.result);
}
public static void Fun(Object obj)
{
var threadObj = obj as ThreadObject;
threadObj.result = threadObj.i + threadObj.j;
}
public class ThreadObject
{
public int i;
public int j;
public int result;
}
попробуйте backgroundWorker http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx вы можете передать значение событию DoWork с помощью DoWorkEventArgs и получить значение в RunWorkerCompleted.
Существует гораздо более простой способ выполнить функцию в отдельном потоке:
// Create function delegate (it can be any delegate)
var FunFunc = new Func<int, int, int>(fun1);
// Start executing function on thread pool with parameters
IAsyncResult FunFuncResult = FunFunc.BeginInvoke(1, 5, null, null);
// Do some stuff
// Wait for asynchronous call completion and get result
int Result = FunFunc.EndInvoke(FunFuncResult);
Эта функция будет выполняться в потоке пула потоков, и эта логика полностью прозрачна для ваше приложение. В общем, я предлагаю выполнять такие небольшие задачи в пуле потоков, а не в выделенном потоке.
Вы должны быть в состоянии использовать анонимный метод или лямбду для обеспечения полной статической проверки:
Thread FirstThread = new Thread(() => Fun1(5, 12));
или если вы хотите что-то сделать с результатом:
Thread FirstThread = new Thread(() => {
int i = Fun1(5, 12);
// do something with i
});
но обратите внимание, что это "что-то сделать" по-прежнему выполняется в контексте нового потока (но с доступом к другим переменным во внешнем методе (Main
) благодаря "захваченным переменным").
Если у вас C# 2.0 (и не выше), то:
Thread FirstThread = new Thread((ThreadStart)delegate { Fun1(5, 12); });
и
Thread FirstThread = new Thread((ThreadStart)delegate {
int i = Fun1(5, 12);
// do something with i
});