I have a method which I call in a new task with
// get the dispatcher for the UI thread
var uiDispatcher = Dispatcher.CurrentDispatcher;
Task.Factory.StartNew(() => BackgroundThreadProc(uiDispatcher));
In the method BackgroundThreadProc() I need a delay of few seconds. I tried it with the DispatcherTimer and the task.delay function but it didn't work. The only thing which worked was the System.Threading.Thread.Sleep(1) but I think the Thread.Sleep() function isn't the best solution.
This is my function:
public void BackgroundThreadProc(Dispatcher uiDispatcher)
{
for (var i = 0; i < 100; i++)
{
var task = Task.Delay(1000).ContinueWith(t =>
{
// create object
var animal = new Animal { Name = "test" + i };
uiDispatcher.Invoke(new Action(() => log(animal)));
});
}
}
As I found out it didn't work because the DispatcherTimer is running in the UI thread. How I can accomplish the delay in the function which is in a other thread than the UI thread?
Update:
Now I tried it with the timer:
public void BackgroundThreadProc(Dispatcher uiDispatcher)
{
for (var i = 0; i < 100; i++)
{
var _delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 1000;
//_delayTimer.Enabled = true;
_delayTimer.Elapsed += delegate
{
var animal = new Animal { Name = "test" + i };
uiDispatcher.Invoke(new Action(() => log(animal)));
_delayTimer.Stop();
};
_delayTimer.Start();
}
}
Use Task.Delay to introduce a delay asynchrnoously:
var task = Task.Delay(1000)
.ContinueWith(t => BackgroundThreadProc());
Are you limited to C# 4.0? I assume you're not, because Task.Delay wouldn't be available.
So, make BackgroundThreadProc an async method and use await inside it:
// get the dispatcher for the UI thread
var uiDispatcher = Dispatcher.CurrentDispatcher;
var task = BackgroundThreadProc(uiDispatcher));
// ...
public async Task BackgroundThreadProc(Dispatcher uiDispatcher)
{
for (var i = 0; i < 100; i++)
{
await Task.Delay(1000).ConfigureAwait(false);
// create object
var animal = new Animal { Name = "test" + i };
uiDispatcher.Invoke(new Action(() => log(animal)));
}
}
You really don't need Task.Factory.StartNew here, the execution will continue on thread pool after await Task.Delay.
Apparently, you're only updating the UI from this BackgroundThreadProc. If that's the case, just remove ConfigureAwait(false) and don't use uiDispatcher.Invoke:
public async Task BackgroundThreadProc()
{
for (var i = 0; i < 100; i++)
{
await Task.Delay(1000);
// create object
var animal = new Animal { Name = "test" + i };
log(animal);
}
}
This loop will be executing asynchronously on the WPF UI thread.
Otherwise, if you do have any other CPU-bound work before Task.Delay, then you may need Task.Factory.StartNew to avoid freezing the UI (note Unwrap):
var task = Task.Factory.StartNew(() =>
BackgroundThreadProc(uiDispatcher)).Unwrap();
You can also use Task.Run, which unwraps the inner task automatically:
var task = Task.Run(() => BackgroundThreadProc(uiDispatcher));
I have a little problem with Threads in this code..
I just want to run a lot of tasks together, and continue when all of them finish.
while (true)
{
// Run tasks together:
foreach (object T in objectsList)
{
if (T.something>0)
var task = Task.Factory.StartNew(() => T.RunObject());
task.ContinueWith(delegate { ChangeObject(T, 1); }, TaskContinuationOptions.NotOnFaulted);
}
// <-- Here I want to wait for all the task to be finish.
// I know its task.Wait() but how to waitAll()?
System.Threading.Thread.Sleep(this.GetNextTime());
var RefreshObjects = new Task(loadObjectsList); RefreshObjects .Start(); RefreshObjects.Wait();
}
I don't know how many objects will be in objectsList and I don't know if T.something will be > 0.
so I can't just use:
Task[] Tasks = new Task[objectsList.count()]
for (int T=0; T<objectsList.count(); ++T)
{
if (objectsList[T].something>0)
var task = Task.Factory.StartNew(() => objectsList[T].RunObject());
task.ContinueWith(delegate { ChangeObject(objectsList[T], 1); }, ...);
}
Task.WaitAll(Tasks);
Because Tasks will contains nulls when objectsList[T].something!>0...
Thanks for any advice!
Just switch the condition and create a List of tasks only for the objects which matches your criteria.
var tasks = objectsList
.Where(x => x.Something() > 0)
.Select(x => {
var task = Task.Factory.StartNew(() => x.RunObject());
task.ContinueWith(t => ChangeObject(....));
return task;
})
.ToArray();
Task.WaitAll(tasks);
Your code sample just waits for RunObject()to complete! If this is desired skip the rest of my answer. If you want to wait for the continuation to complete, too you can use this
var tasks = objectsList
.Where(x => x.Something() > 0)
.Select(x => Task.Factory.StartNew(() => x.RunObject()).ContinueWith(t => ChangeObject(....)))
.ToArray();
Task.WaitAll(tasks);
because ContinueWith generates a new Task.
If objectsList implements IEnumerable, (as an array does),
(And there are less than 64 objects in the list), you can use this:
public delegate void SyncDelegatesInParallelDelegate<in T>(T item);
public static class ParallelLinqExtensions
{
public static void SyncDelegatesInParallel<T>(
this IEnumerable<T> list,
SyncDelegatesInParallelDelegate<T> action)
{
var foundCriticalException = false;
Exception exception = null;
var waitHndls = new List<WaitHandle>();
foreach (var item in list)
{
// Temp copy of session for modified closure
var localItem = item;
var txEvnt = new ManualResetEvent(false);
// Temp copy of session for closure
ThreadPool.QueueUserWorkItem(
depTx =>
{
try { if (!foundCriticalException) action(localItem); }
catch (Exception gX)
{ exception = gX; foundCriticalException = true; }
finally { txEvnt.Set(); }
}, null);
waitHndls.Add(txEvnt);
}
if (waitHndls.Count > 0) WaitHandle.WaitAll(waitHndls.ToArray());
if (exception != null) throw exception;
}
}
you would call it like this
objectsList.SyncDelegatesInParallel(delegate { ChangeObject(T, 1);});
I have a problem in Asp.net C#
I have the code below :
List objectList = new List();
foreach(var item in listItem)
{
object obj = getData (item);
objectList.add(obj);
}
Console.Write("Finish all");
Each time `getData (item);' fires it takes about 1s;
I want all items in listItem to run at the same time and then execute after foreach finishes the Console.write("Finish all")
How can I do that?
Any idea will be appreciated!
You can try Parallel.Foreach.Where each iterations may run in parallel.
You can use Task to get it done:
var tasks = listItem.Select(item => Task.Factory.StartNew(() => aaa()));
Task.WaitAll(tasks.ToArray());
Console.Write();
If you don't need to wait all tasks finish, just skip WaitAll:
var tasks = listItem.Select(item => Task.Factory.StartNew(() => aaa()));
Console.Write();
For .NET 3.5, you can use ThreadPool:
listItem.ForEach(item => ThreadPool.QueueUserWorkItem(state => aaa()));
Console.Write();
using System.Threading;
using System.Threading.Tasks;
List<Task> tasks = new List<Task>();
foreach(item in listItem)
{
tasks.Add(Task.Factory.StartNew(() => aaa()));
}
// If you want the Console.Writeline to execute immediately after starting the tasks
Console.Writeline();
Task.WaitAll(tasks.ToArray());
Console.Writeline("Finised executing all tasks");
And if you want use Threads to do this, you can:
List<ManualResetEvent> resetEvents = new List<ManualResetEvent>();
.
.
.
foreach(item in lisItem)
{
Thread thread = new Thread(new ParameterizedThreadStart(aaa));
ManualResetEvent resetEvent = new ManualResetEvent(false);
resetEvents.Add(resetEvent);
thread.Start(resetEvent);
}
Console.WriteLine();
WaitHandle.WaitAll(resetEvents.ToArray<WaitHandle>());
Console.WriteLine("Finised executing all threads");
}
}
.
.
.
void aaa(object data)
{
ManualResetEvent resetEvent = data as ManualResetEvent;
// completed execution
Console.WriteLine(".");
resetEvent.Set();
}
int itemCount = ItemList.Count;
List<object> objectList = new List<object>();
ManualResetEvent[] resetEvents = new ManualResetEvent[itemCount];
for (int i = 0; i < itemCount; i++)
{
var item= ItemList[i];
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback((object index) =>
{
ItemCalEvent item = getData(item);
lock (objectList)
objectList.Add(item);
resetEvents[(int)index].Set();
}), i);
}
WaitHandle.WaitAll(resetEvents);
This is good in .net 3.5
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.
I have async methods that returns an objects
public static IEnumerable<Users.User> GetUsers(IEnumerable<string> uids, Field fields)
{
Task<ResponseApi<Users.User>>[] tasks;
tasks = uids.Select(uid =>
{
var parameters = new NameValueCollection
{
{"uids", uid},
{"fields", FieldsUtils.ConvertFieldsToString(fields)}
};
return GetUserResponseApi(parameters);
}).ToArray();
Task.WaitAll(tasks);
foreach(Task<ResponseApi<Users.User>> task in tasks)
{
if(task.Result.Response != null)
{
yield return task.Result.Response;
}
}
}
And I want to update UI in other method,UI maybe don't update because method GetUserResponseApi don't return any value.
public static Task<ResponseApi<Users.User>> GetUserResponseApi(NameValueCollection parameters)
{
return CallMethodApi("users.get", parameters, CallType.HTTPS)
.ContinueWith(
r =>
{
//don't execute
var responseApi = new ResponseApi<Users.User>();
responseApi.Response = JsonConvert.DeserializeObject<Users.User>(r.Result["response"][0].ToString());
return responseApi;
});
}
private void BtnGetUsersClick(object sender, EventArgs e)
{
var random = new Random();
int max = 175028595;
var uids = new List<string>();
for(int i = 1; i <= 20; i++)
{
uids.Add((random.Next(max) + 1).ToString());
}
Task.Factory.StartNew(() =>
{
var users = VkontakteApi.GetUsers(uids, Field.Online);
foreach(var user in users)
{
richTextBox1.Text += string.Format("ID:{0} online:{1}", user.uid,
user.online);
}
}, CancellationToken.None, TaskCreationOptions.None, _uiContext);
}
How to resolve problem with ContinueWith in GetUserResponseApi?
UPDATE:
I think that problem in method GetUserResponseApi because block ContinueWith doesn't execute.
Use Application.Current.Dispatcher to dispatch calls to UI thread whenever you access UI objects.
Application.Current.Dispatcher.Invoke(() => {
try
{
richTextBox1.Text += string.Format("ID:{0} online:{1}", user.uid, user.online);
}
catch
{
//handle
}
), DispatcherPriority.Background);
Try using TaskScheduler.FromCurrentSynchronizationContext() method:
Task.Factory.StartNew(() =>
{
var users = VkontakteApi.GetUsers(uids, Field.Online);
foreach(var user in users)
{
richTextBox1.Text += string.Format("ID:{0} online:{1}", user.uid,
user.online);
}
}, CancellationToken.None,
TaskScheduler.FromCurrentSynchronizationContext());