Problem with Invoke to parallelize foreach - c#

I have a problem with using System.Threading.Tasks.Parallel.ForEach. The body foreach progressBar want to update.
But Invoke method sometimes freeze.
I attach the code to the form which is prograssbar and Buton.
private void button1_Click(object sender, EventArgs e)
{
DateTime start = DateTime.Now;
pforeach();
Text = (DateTime.Now - start).ToString();
}
private void pforeach()
{
int[] intArray = new int[60];
int totalcount = intArray.Length;
object lck = new object();
System.Threading.Tasks.Parallel.ForEach<int, int>(intArray,
() => 0,
(x, loop, count) =>
{
int value = 0;
System.Threading.Thread.Sleep(100);
count++;
value = (int)(100f / (float)totalcount * (float)count);
Set(value);
return count;
},
(x) =>
{
});
}
private void Set(int i)
{
if (this.InvokeRequired)
{
var result = Invoke(new Action<int>(Set), i);
}
else
progressBar1.Value = i;
}
Sometimes it passes without a problem, but usually it freeze on
var result = Invoke (new Action <int> (Set), i).
Try to kick me in the problem.
Thank you.

Your problem is that Invoke (and queueing a Task to the UI TaskScheduler) both require the UI thread to be processing its message loop. However, it is not. It is still waiting for the Parallel.ForEach loop to complete. This is why you see a deadlock.
If you want the Parallel.ForEach to run without blocking the UI thread, wrap it into a Task, as such:
private TaskScheduler ui;
private void button1_Click(object sender, EventArgs e)
{
ui = TaskScheduler.FromCurrentSynchronizationContext();
DateTime start = DateTime.Now;
Task.Factory.StartNew(pforeach)
.ContinueWith(task =>
{
task.Wait(); // Ensure errors are propogated to the UI thread.
Text = (DateTime.Now - start).ToString();
}, ui);
}
private void pforeach()
{
int[] intArray = new int[60];
int totalcount = intArray.Length;
object lck = new object();
System.Threading.Tasks.Parallel.ForEach<int, int>(intArray,
() => 0,
(x, loop, count) =>
{
int value = 0;
System.Threading.Thread.Sleep(100);
count++;
value = (int)(100f / (float)totalcount * (float)count);
Task.Factory.StartNew(
() => Set(value),
CancellationToken.None,
TaskCreationOptions.None,
ui).Wait();
return count;
},
(x) =>
{
});
}
private void Set(int i)
{
progressBar1.Value = i;
}

I was looking at how I did this and this change may help you:
In my constructor I have this line:
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Then I do this:
private void changeProgressBar()
{
(new Task(() =>
{
mainProgressBar.Value++;
mainProgressTextField.Text = mainProgressBar.Value + " of " + mainProgressBar.Maximum;
})).Start(uiScheduler);
}
This gets rid of needing to use Invoke, and if you use the Task method then it may solve your problem.
I think these were all in System.Threading.Tasks;

Related

Queue of BackgroundWorkers raise event when complete [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I need to execute n BackgroundWorkers, when they're complete I want to raise an event and do something with the result of all their work. My use case it to make the queue, fill it, then run it only once. To accomplish this I made a class ParallelQueue. With my initial testing it seems to work, however I'm concerned that the condition _max == _iteration is not the best was to evaluate all work in the queue has been done. Or that my use of Queue is not thread safe, what should I use to accomplish this? (ConcurrentQueue?) If this question is too general I'll remove it, Thanks.
public class ParallelQueue
{
private Queue<BackgroundWorker> _queue;
private readonly object _key = new object();
private int _max = 0;
private int _iteration = 0;
private bool _ran = false;
public ParallelQueue()
{
_queue = new Queue<BackgroundWorker>();
}
public delegate void BackgroundQueueCompleted(object sender, RunWorkerCompletedEventArgs e);
public event BackgroundQueueCompleted QueueCompleted;
public void Add(BackgroundWorker worker)
{
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
_queue.Enqueue(worker);
}
public void Run()
{
lock (_key)
{
if(!_queue.Any()) throw new ArgumentOutOfRangeException("ParallelQueue cannot be empty");
if (_ran) throw new InvalidOperationException("ParallelQueue can only be run once");
_ran = true;
_max = _queue.Count();
Parallel.For(0, _queue.Count, (i, state) =>
{
BackgroundWorker worker = _queue.Dequeue();
worker.RunWorkerAsync();
});
}
}
private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Interlocked.Increment(ref _iteration);
if (_max == _iteration)
{
QueueCompleted?.Invoke(this, e);
}
}
}
example using ParallelQueue
public class Program
{
static void Main(string[] args)
{
var queue = new ParallelQueue();
queue.QueueCompleted += MyQueueCompletedHandler;
for (int i = 0; i < 10; i++)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler((sender, e) =>
{
Thread.Sleep(500);
});
queue.Add(bw);
}
queue.Run();
Console.ReadLine();
}
private static void MyQueueCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("queue is complete");
}
}
The BackgroundWorker class has become practically obsolete after the introduction of the Task Parallel Library (TPL) in 2010. If the results of the work you have to do is homogeneous, you can just use the Parallel.ForEach method, or, if you are familiar with LINQ, use PLINQ. Here is a PLINQ example:
var input = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] results = input
.AsParallel()
.AsOrdered() // optional
.WithDegreeOfParallelism(2) // optional
.Select(x => { Thread.Sleep(500); return x * 2; }) // simulate some work
.ToArray();
If the results are heterogeneous, you can create a Task<TResult> for each piece of work, store it in a List<Task>, wait all the tasks, and get the results through the Result property of each. Example:
var task1 = Task.Run(() => { Thread.Sleep(500); return 1; });
var task2 = Task.Run(() => { Thread.Sleep(500); return "Helen"; });
var task3 = Task.Run(() => { Thread.Sleep(500); return DateTime.Now; });
var list = new List<Task>() { task1, task2, task3 };
Task.WaitAll(list.ToArray());
int result1 = task1.Result;
string result2 = task2.Result;
DateTime result3 = task3.Result;

Is it possible always to force a new thread with Task?

I am trying to create a new thread each time Task.Factory.StartNew is called. The question is how to run the code bellow without throwing the exception:
static void Main(string[] args)
{
int firstThreadId = 0;
Task.Factory.StartNew(() => firstThreadId = Thread.CurrentThread.ManagedThreadId);
for (int i = 0; i < 100; i++)
{
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep(1000);
if (firstThreadId == Thread.CurrentThread.ManagedThreadId)
throw new Exception("The first thread is reused.");
}
});
}
Console.Read();
}
EDIT: the new code if you comment the first for statement there is no problem. But if you have it, WOW, the message "Thread reused" is written to the console. Can you explain that because I am really confused.
static void Main(string[] args)
{
ConcurrentDictionary<int, int> startedThreads = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() =>
{
startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.ManagedThreadId, (a, b) => b);
}, TaskCreationOptions.LongRunning);
for (int j = 0; j < 100; j++)
{
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep(10);
if (startedThreads.ContainsKey(
Thread.CurrentThread.ManagedThreadId))
Console.WriteLine("Thread reused");
}
}, TaskCreationOptions.LongRunning);
}
});
}
Console.Read();
}
If you specify TaskCreationOptions.LongRunning when starting the task, that provides a hint to the scheduler, which the default scheduler takes as an indicator to create a new thread for the task.
It's only a hint - I'm not sure I'd rely on it... but I haven't seen any counterexamples using the default scheduler.
Adding to Jon Skeet's answer, if you want to guarantee that a new thread is created every time, you can write your own TaskScheduler that creates a new thread.
Try this:
var taskCompletionSource = new TaskCompletionSource<bool>();
Thread t = new Thread(() =>
{
try
{
Operation();
taskCompletionSource.TrySetResult(true);
}
catch (Exception e)
{
taskCompletionSource.TrySetException(e);
}
});
void Operation()
{
// Some work in thread
}
t.Start();
await taskCompletionSource.Task;
You also can write extension methods for Action, Func and so on.
For example:
public static Task RunInThread(
this Action action,
Action<Thread> initThreadAction = null)
{
TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
Thread thread = new Thread(() =>
{
try
{
action();
taskCompletionSource.TrySetResult(true);
}
catch (Exception e)
{
taskCompletionSource.TrySetException(e);
}
});
initThreadAction?.Invoke(thread);
thread.Start();
return taskCompletionSource.Task;
}
or
public static Task<TResult> RunInThread<T1, T2, TResult>(
this Func<T1, T2, TResult> function,
T1 param1,
T2 param2,
Action<Thread> initThreadAction = null)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
Thread thread = new Thread(() =>
{
try
{
TResult result = function(param1, param2);
taskCompletionSource.TrySetResult(result);
}
catch (Exception e)
{
taskCompletionSource.TrySetException(e);
}
});
initThreadAction?.Invoke(thread);
thread.Start();
return taskCompletionSource.Task;
}
and use it like that:
var result = await some_function.RunInThread(param1, param2).ConfigureAwait(true);
Hello and thank you all for the answers. You all got +1. All suggested solution did not work for my case. The problem is that when you sleep a thread it will be reused at some point of time. The people above suggested:
using LongRunning => This will not work if you have nested/child
tasks
custom task scheduler => I tried to write my own and also tried this
ThreadPerTaskScheduler which also di not work.
using pure threads => Still failing...
you could also check this project at Multithreading.Scheduler github
My solution
I don't like it but it works. Basically I block the thread so it cannot be reused. Bellow are the extension methods and a working example. Again, thank you.
https://gist.github.com/4150635
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
public static class ThreadExtensions
{
/// <summary>
/// Blocks the current thread for a period of time so that the thread cannot be reused by the threadpool.
/// </summary>
public static void Block(this Thread thread, int millisecondsTimeout)
{
new WakeSleepClass(millisecondsTimeout).SleepThread();
}
/// <summary>
/// Blocks the current thread so that the thread cannot be reused by the threadpool.
/// </summary>
public static void Block(this Thread thread)
{
new WakeSleepClass().SleepThread();
}
/// <summary>
/// Blocks the current thread for a period of time so that the thread cannot be reused by the threadpool.
/// </summary>
public static void Block(this Thread thread, TimeSpan timeout)
{
new WakeSleepClass(timeout).SleepThread();
}
class WakeSleepClass
{
bool locked = true;
readonly TimerDisposer timerDisposer = new TimerDisposer();
public WakeSleepClass(int sleepTime)
{
var timer = new Timer(WakeThread, timerDisposer, sleepTime, sleepTime);
timerDisposer.InternalTimer = timer;
}
public WakeSleepClass(TimeSpan sleepTime)
{
var timer = new Timer(WakeThread, timerDisposer, sleepTime, sleepTime);
timerDisposer.InternalTimer = timer;
}
public WakeSleepClass()
{
var timer = new Timer(WakeThread, timerDisposer, Timeout.Infinite, Timeout.Infinite);
timerDisposer.InternalTimer = timer;
}
public void SleepThread()
{
while (locked)
lock (timerDisposer) Monitor.Wait(timerDisposer);
locked = true;
}
public void WakeThread(object key)
{
locked = false;
lock (key) Monitor.Pulse(key);
((TimerDisposer)key).InternalTimer.Dispose();
}
class TimerDisposer
{
public Timer InternalTimer { get; set; }
}
}
}
class Program
{
private static readonly Queue<CancellationTokenSource> tokenSourceQueue = new Queue<CancellationTokenSource>();
static void Main(string[] args)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
tokenSourceQueue.Enqueue(tokenSource);
ConcurrentDictionary<int, int> startedThreads = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
Task.Factory.StartNew(() =>
{
startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b);
for (int j = 0; j < 50; j++)
Task.Factory.StartNew(() => startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b));
for (int j = 0; j < 50; j++)
{
Task.Factory.StartNew(() =>
{
while (!tokenSource.Token.IsCancellationRequested)
{
if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused");
Thread.CurrentThread.Block(10);
if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused");
}
}, tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
.ContinueWith(task =>
{
WriteExceptions(task.Exception);
Console.WriteLine("-----------------------------");
}, TaskContinuationOptions.OnlyOnFaulted);
}
Thread.CurrentThread.Block();
}, tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)
.ContinueWith(task =>
{
WriteExceptions(task.Exception);
Console.WriteLine("-----------------------------");
}, TaskContinuationOptions.OnlyOnFaulted);
}
Console.Read();
}
private static void WriteExceptions(Exception ex)
{
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
WriteExceptions(ex.InnerException);
}
}
}
Just start threads with new Thread() and then Start() them
static void Main(string[] args)
{
ConcurrentDictionary<int, int> startedThreads = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 10; i++)
{
new Thread(() =>
{
new Thread(() =>
{
startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b);
}).Start();
for (int j = 0; j < 100; j++)
{
new Thread(() =>
{
while (true)
{
Thread.Sleep(10);
if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId))
Console.WriteLine("Thread reused");
}
}).Start();
}
}).Start();
}
Console.Read();
}
Tasks are supposed to be managed by the scheduler. The whole idea of Tasks is that the runtime will decide when a new thread is needed. On the other hand if you do need different threads chances are something else in the code is wrong like overdependency on Thread.Sleep() or thread local storage.
As pointed out you can create your own TaskScheduler and use tasks to create threads but then why use Tasks to begin with?
Here is a custom TaskScheduler that executes the tasks on a dedicated thread per task:
public class ThreadPerTask_TaskScheduler : TaskScheduler
{
protected override void QueueTask(Task task)
{
var thread = new Thread(() => TryExecuteTask(task));
thread.IsBackground = true;
thread.Start();
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return TryExecuteTask(task);
}
protected override IEnumerable<Task> GetScheduledTasks() { yield break; }
}
Usage example:
var parallelOptions = new ParallelOptions()
{
MaxDegreeOfParallelism = 3,
TaskScheduler = new ThreadPerTask_TaskScheduler()
};
Parallel.ForEach(Enumerable.Range(1, 10), parallelOptions, item =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}]" +
$" Processing #{item}" +
(Thread.CurrentThread.IsBackground ? ", Background" : "") +
(Thread.CurrentThread.IsThreadPoolThread ? ", ThreadPool" : ""));
Thread.Sleep(1000); // Simulate CPU-bound work
});
Output:
20:38:56.770 [4] Processing #3, Background
20:38:56.770 [5] Processing #2, Background
20:38:56.770 [1] Processing #1
20:38:57.782 [1] Processing #4
20:38:57.783 [8] Processing #5, Background
20:38:57.783 [7] Processing #6, Background
20:38:58.783 [1] Processing #7
20:38:58.783 [10] Processing #8, Background
20:38:58.787 [9] Processing #9, Background
20:38:59.783 [1] Processing #10
Try it on Fiddle.
This custom TaskScheduler allows the current thread to participate in the computations too. This is demonstrated in the above example by the thread [1] processing the items #1, #4, #7 and #10. If you don't want this to happen, just replace the code inside the TryExecuteTaskInline with return false;.
Another example, featuring the Task.Factory.StartNew method. Starting 100 tasks on 100 different threads:
var oneThreadPerTask = new ThreadPerTask_TaskScheduler();
Task[] tasks = Enumerable.Range(1, 100).Select(_ =>
{
return Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // Simulate long-running work
}, default, TaskCreationOptions.None, oneThreadPerTask);
}).ToArray();
In this case the current thread is not participating in the work, because all tasks are started behind the scenes by invoking their Start method, and not the
RunSynchronously.

Waiting on multiple background threads

I want know when all thread has been finished in a multithread program
without something like pooling
while(!allThreadFinished){
thread.sleep(100);
}
The solution should be used Monitor but i can't how can i approve that it's correct.
since the "SomeMethod" in the following code using network, it consume times.
public object SomeMethod(string input);
public object[] MultiThreadMethod(string[] inputs) {
var result = new object[inputs.Count()];
int i = 0;
foreach (var item in inputs) {
BackgroundWorker work = new BackgroundWorker();
work.DoWork += (sender, doWorkEventArgs) => { doWorkEventArgs.Result = SomeMethod(item); };
work.RunWorkerCompleted += (sender, runWorkerCompletedEventArgs) => {
result[i] = runWorkerCompletedEventArgs.Result;
};
i++;
work.RunWorkerAsync();
}
/////////////////////////////////////////////////////////////
//**wait while all thread has been completed**
/////////////////////////////////////////////////////////////
return result;
}
Try using the TPL http://msdn.microsoft.com/en-us/library/dd460717.aspx.
List<Task> tasks = new List<Task>();
Task t1 = new Task(() =>
{
// Do something here...
});
t1.Start();
tasks.Add(t1);
Task t2 = new Task(() =>
{
// Do something here...
});
t2.Start();
tasks.Add(t2);
Task.WaitAll(tasks.ToArray());
You can use TPL to do the same, you will avoid using Thread.Sleep(), and it will be much clearer. Check this out: http://msdn.microsoft.com/en-us/library/dd537610.aspx
Your example with TPL would look like this (untested code):
private ConcurrentBag<object> _results;
public object[] MultiThreadMethod(string[] inputs)
{
_results = new ConcurrentBag<object>();
var tasks = new Task[inputs.Length];
for (int i = 0; i < inputs.Length; i++)
{
tasks[i] = Task.Factory.StartNew(() => DoWork(inputs[i]));
}
Task.WaitAll(tasks);
return _results.ToArray();
}
private void DoWork(string item)
{
_results.Add(SomeMethod(item));
}
EDIT: Without ConcurrentBag:
public object[] MultiThreadMethod(string[] inputs)
{
var tasks = new Task<object>[inputs.Length];
for (int i = 0; i < inputs.Length; i++)
{
tasks[i] = Task<object>.Factory.StartNew(() => DoWork(inputs[i]));
}
Task.WaitAll(tasks);
return tasks.Select(task => task.Result).ToArray();
}
private object DoWork(string item)
{
return SomeMethod(item);
}
Hook the RunWorkerCompleted event on the BackgroundWorker. It will fire when the work is done.
A complete example of how to use the BackgroundWorker properly can be found here.
http://msdn.microsoft.com/en-us/library/dd537608.aspx
// Sequential version
foreach (var item in sourceCollection)
Process(item);
// Parallel equivalent
Parallel.ForEach(sourceCollection, item => Process(item));

Recursive Task Queue

I'm trying to iterate through a queue - taking 1 item from the queue, processing it in a background task, updating the UI, and then taking the next item, and so on. The problem is the first item is processed in a background task (thread) but then the subsequent items are processed in the UI thread - blocking the UI.
Does anyone know why this happens and how to get around this problem? My full test code is below. Note: this code is for my learning and future reference - not any real application.
public partial class MainWindow : Window
{
private Queue<int> testQueue = new Queue<int>();
private TaskScheduler uiScheduler;
public MainWindow()
{
InitializeComponent();
this.uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
this.testQueue = new Queue<int>();
this.testQueue.Enqueue(3);
this.testQueue.Enqueue(6);
this.testQueue.Enqueue(7);
this.testQueue.Enqueue(11);
this.testQueue.Enqueue(13);
}
// just a method that takes about 1 second to run on a modern pc
private double SumRootN(int root)
{
double result = 0;
for (int i = 1; i < 10000000; i++)
{
result += Math.Exp(Math.Log(i) / root);
}
return result;
}
private void testQueueButton_Click(object sender, RoutedEventArgs e)
{
this.processQueue();
}
private void processQueue()
{
if (this.testQueue.Count > 0)
{
int root = this.testQueue.Dequeue();
Task<double>.Factory.StartNew(() => SumRootN(root))
.ContinueWith(t =>
{
this.statusText.Text += String.Format("root {0} : {1}\n", root, t.Result);
this.processQueue();
}, uiScheduler);
}
else
{
this.statusText.Text += "Done\n";
}
}
}
Thank you for posting a repro which allowed me to debug.
Task.Factory.StartNew runs your task on the scheduler (factoryScheduler ?? currentTaskScheduler ?? threadPoolScheduler). You got into case 2: Your new task inherits the scheduler from its parent.
I noticed your curious use of recursive calls in order to simulate a loop. If you do it like this, the problem goes away:
Task<double>.Factory.StartNew(() => SumRootN(root))
.ContinueWith(t =>
{
this.statusText.Text += String.Format("root {0} : {1}\n", root, t.Result);
}, uiScheduler).ContinueWith(t => { this.processQueue(); });
That's because you are using TaskScheduler.FromCurrentSynchronizationContext() - you do know what it does right? (makes it run on the same thread it is called, in your case the UI)
EDIT: usr answered you why is that happening, but you could also do this (for a quasi parallel processing):
int root = this.testQueue.Dequeue();
Task<double>.Factory.StartNew(() => SumRootN(root))
.ContinueWith(t =>
{
this.statusText.Text += String.Format("root {0} : {1}\n", root, t.Result);
}, uiScheduler);
this.processQueue();

How to call the method in thread with arguments and return some value

I like to call the method in thread with arguments and return some value here example
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);
}
}
}
I know this above example run successfully but if method fun1 like this
public int fun1(int i,int j)
{
int k;
k=i+j;
return k;
}
then how can I call this in thread?
You should be able to use an anonymous method or lambda to provide full static checking:
Thread FirstThread = new Thread(() => Fun1(5, 12));
or if you want to do something with the result:
Thread FirstThread = new Thread(() => {
int i = Fun1(5, 12);
// do something with i
});
but note that this "do something" still runs in the context of the new thread (but with access to the other variables in the outer method (Main) courtesy of "captured variables").
If you have C# 2.0 (and not above), then:
Thread FirstThread = new Thread((ThreadStart)delegate { Fun1(5, 12); });
and
Thread FirstThread = new Thread((ThreadStart)delegate {
int i = Fun1(5, 12);
// do something with i
});
This may be another approach. Here input is passed as parameterized Thread and return type is passed in the delegate event, so that when the thread complete that will call the Delegate. This will be fine to get result when the thread completes.
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);
}
}
I like Mark Gravell's answer. You can pass your result back out to the main thread with just a little modification:
int fun1, fun2;
Thread FirstThread = new Thread(() => {
fun1 = Fun1(5, 12);
});
Thread SecondThread = new Thread(() => {
fun2 = Fun2(2, 3);
});
FirstThread.Start();
SecondThread.Start();
FirstThread.Join();
SecondThread.Join();
Console.WriteLine("Fun1 returned {0}, Fun2 returned {1}", fun1, fun2);
There is much simpler way to execute function in separate thread:
// 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);
This function will be executed on thread pool thread, and that logic is completely transparent to your application.
An in general, I suggest to execute such small tasks on thread pool instead of dedicated thread.
You can use the ParameterizedThreadStart overload on the Thread constructor. It allows you to pass an Object as a parameter to your thread method. It's going to be a single Object parameter, so I usually create a parameter class for such threads.. This object can also store the result of the thread execution, that you can read after the thread has ended.
Don't forget that accessing this object while the thread is running is possible, but is not "thread safe". You know the drill :)
Here's an example:
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;
}
For some alternatives; 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));
or write your own capture-type (this is broadly comparable to what the compiler does for you when you use anon-methods / lambdas with captured variables, but has been implemented differently):
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
try backgroundWorker http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx you can pass value to the DoWork event with DoWorkEventArgs and retrive value in the RunWorkerCompleted.

Categories