When starting multiple threads, the id parameter I'm parsing is sometimes wrong. Here is my startup:
for (int i = 0; i < _threadCount; i++)
{
Thread thread = new Thread(() => WorkerThread(i));
thread.Start();
_threads.Add(thread);
}
And my thread function:
private void WorkerThread(int id)
{
Console.WriteLine("[{0}] Thread started {1}", DateTime.Now.ToLongTimeString(), id);
}
The output of this code is:
[19:10:54] Thread start 3
[19:10:54] Thread start 9
[19:10:54] Thread start 4
[19:10:54] Thread start 12
[19:10:54] Thread start 11
[19:10:54] Thread start 3
[19:10:54] Thread start 12
[19:10:54] Thread start 6
[19:10:54] Thread start 9
[19:10:54] Thread start 6
[19:10:54] Thread start 13
[19:10:54] Thread start 2
[19:10:54] Thread start 15
[19:10:54] Thread start 9
[19:10:54] Thread start 15
Where in my mind, this code should create every thread with a unique id instead of duplicates as seen above.
Compiler info:
Platform target: x64
Target Framework: .NET Framework 4.5
You should be careful about accidentally modifying captured variables like i after starting the thread, because the i is shared. The i variable refers to the same memory location throughout the loop’s lifetime. The solution is to use a temporary variable like this:
for (int i = 0; i < _threadCount; i++)
{
var i1 = i;
Thread thread = new Thread(() => WorkerThread(i1));
thread.Start();
_threads.Add(thread);
}
Read more about Closures here : The Beauty of Closures from (Jon Skeet) and Lambda expressions and captured variables from (Joseph Albahari).
The problem is that the i variable refers to the same memory location through the loop's lifetime. Therefore, each thread calls on a variable whose value may change as it is running. The solution is to user a temporary variable int temp = i. as #Salah Akbari said.
Related
I have an app (http web load test app) that need new Thread() , and the HttpClient only have async method, so how do I run the action synchronous
ps: I tried use full Task but the thread number it use is low (30 thread only),
so I want to try the Thread to see if it can be much faster.
Will the .GetAwaiter().GetResult() cost 2 thread (100 thread became 200 thread) ?
previous I use
for(var i = 0; i< 200;i++)
{
Task.Run(async ()=>
{
while(thereStillHaveRequestToMake)
{
await httpclient.SendAsync() // some thing like this
}
});
}
// the prolem is there are only 30-40 Thread in use (From TaskManager)
So I want to switch to use Thread directly
for(var i = 0; i< 200;i++)
{
new Thread(()=>
{
while(thereStillHaveRequestToMake)
{
httpclient.SendAsync().GetAwaiter.GetResult()
}
});
}
I have an app (http web load test app) that need new Thread()
Why?
HttpClient only have async method, so how do I run the action synchronously
Why.
Or How to call asynchronous method from synchronous method in C#?.
I tried use full Task but the thread number it use is low (30 thread only),
A task is not a thread. We can easily test this by running methods on the thread pool. First we set the ThreadPool to only allow a single thread.
class Program
{
private const int MaxThreads = 1;
static void Main(string[] args)
{
ThreadPool.SetMinThreads(MaxThreads, 1);
Console.WriteLine(ThreadPool.SetMaxThreads(MaxThreads, 1));
Task.Run(() => SomeMethod(new StateInfo { Order = 0, WaitFor = 3000 }));
Task.Run(() => SomeMethod(new StateInfo { Order = 1, WaitFor = 3000 }));
Task.Run(() => SomeMethod(new StateInfo { Order = 2, WaitFor = 3000 }));
Console.WriteLine("Main thread does some work, then sleeps.");
Thread.Sleep(5000);
Console.WriteLine("Main thread exits.");
}
static void SomeMethod(Object stateInfo)
{
var si = (StateInfo)stateInfo;
Console.WriteLine($"Hello from the thread pool. {si.Order}");
Thread.Sleep(si.WaitFor);
}
public class StateInfo
{
public int Order { get; set; }
public int WaitFor { get; set; }
}
}
Output
True
Main thread does some work, then sleeps.
Hello from the thread pool. 1
Hello from the thread pool. 2
Main thread exits.
Since we have 1 thread and we've told the first two methods to wait a total of 6 seconds, but the main thread exits after 5 seconds, we never get a message from the 3rd method. We can easily test this by changing MaxThreads = 2 which yields something like the following (we get 3 results, but not necessarily in order):
True
Main thread does some work, then sleeps.
Hello from the thread pool. 1
Hello from the thread pool. 2
Hello from the thread pool. 3
Main thread exits.
Now that we've guaranteed we're using a single thread, lets see how many requests we can do simultaneously synchronously.
static void SomeMethod(Object stateInfo)
{
var si = (StateInfo)stateInfo;
Console.WriteLine($"Hello from the thread pool. {si.Order}");
httpClient.GetStringAsync($"https://www.google.com");
Console.WriteLine($"Hello from the thread pool. {si.Order} finished");
}
Since we aren't async/await the request, it runs synchronously so the output is predictably:
True
Main thread does some work, then sleeps.
Hello from the thread pool. 1
Hello from the thread pool. 1 finished
Hello from the thread pool. 2
Hello from the thread pool. 2 finished
Hello from the thread pool. 3
Hello from the thread pool. 3 finished
Main thread exits.
That doesn't really load test anything because synchronous calls wait until the previous one finishes. In order to load test we want many concurrent calls. This is easily done with a single thread using async await.
Update the method:
static async Task SomeMethod(Object stateInfo)
{
var si = (StateInfo)stateInfo;
Console.WriteLine($"Hello from the thread pool. {si.Order}");
await httpClient.GetStringAsync($"https://www.google.com");
Console.WriteLine($"Hello from the thread pool. {si.Order} finished");
}
Use linq to make a list of requests, and wait for all of them to finish.
static void Main(string[] args)
{
ThreadPool.SetMinThreads(MaxThreads, 1);
Console.WriteLine(ThreadPool.SetMaxThreads(MaxThreads, 1));
Console.WriteLine("Start Requests");
var requests = Enumerable.Range(0, 200)
.Select(async (x) => await Task.Run(() => SomeMethod2(new StateInfo { Order = x, WaitFor = 0 })))
.ToArray();
Console.WriteLine("Wait for them.");
Task.WaitAll(requests.ToArray());
Console.WriteLine("Main thread exits.");
Console.ReadKey();
}
Yields (I didn't want to put 400 lines of code here)
True
Start Requests
Wait for them.
Hello from the thread pool. 0
Hello from the thread pool. 1
Hello from the thread pool. 2
.... repeating to
Hello from the thread pool. 199
Hello from the thread pool. 178 finished
Hello from the thread pool. 5 finished
Hello from the thread pool. 3 finished
Hello from the thread pool. 15 finished
Hello from the thread pool. 26 finished
Hello from the thread pool. 4 finished
.... repeating until all 200 requests are finished
Main thread exits.
200 Http Requests on a single thread. Why do you need more threads?
I am playing a little bit with ConfigureAwait because I would like to understand how it works.
Therfore, I wrote the following small console application (actually running in LINQPad):
void Main()
{
// Use dispatcher to execute the code on STA thread
Dispatcher.CurrentDispatcher.Invoke(() => Run());
}
private async static Task Run()
{
var continueOnCapturedContext1 = true;
var continueOnCapturedContext2 = true;
PrintThreadID();
await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext1);
PrintThreadID();
await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext2);
PrintThreadID();
}
private static void PrintThreadID()
{
Console.Write(Thread.CurrentThread.ManagedThreadId.ToString("00") + "\t");
}
And I got the following output:
A) true/true
var continueOnCapturedContext1 = true;
var continueOnCapturedContext2 = true;
1) 11 19 11 07 11
2) 11 09 11 12 11
3) 11 06 11 06 11
Expected: dispatcher thread (11) was captured and awaitable tasks were executed on different or same threadpool threads.
B) false/false
var continueOnCapturedContext1 = false;
var continueOnCapturedContext2 = false;
1) 11 23 23 22 22
2) 11 19 19 19 19
3) 11 10 10 10 10
Also expected: SynchronizationContext was not captured, so subsequent awaitable and non-awaitable code were run on threadpool thread (usually the same).
C) false/true
var continueOnCapturedContext1 = false;
var continueOnCapturedContext2 = true;
1) 11 14 14 06 06
2) 11 20 20 20 20
3) 11 17 17 08 08
The result of output 1 and 3 is strange. The 2. awaitbale task was executed with option "continue on captured context" so I would expect that it runs on the same thread as the code that called it.
It seems, that ConfigureAwait(true/false) has no effect on subsequent awaitable calls if it was alreay called before, right?
The 2. awaitbale task was executed with option "continue on captured context" so I would expect that it runs on the same thread as the code that called it.
That assumes that "context == thread", but it doesn't. The synchronization context that uses the thread-pool will resume on any thread in the thread-pool. Now if you don't capture the synchronization context, you'll still end up on "a thread in the thread pool".
So yes, if you're already on a thread-pool thread, it won't matter whether or not you capture the synchronization context... the continuation will still end up on a thread pool thread. But it's worth pointing out that it would be entirely reasonable to have a different synchronization context with multiple threads, and capturing the synchronization context would return to one of those threads, but not necessarily the same one.
It seems, that ConfigureAwait(true/false) has no effect on subsequent awaitable calls if it was already called before, right?
Not quite. That will be the case if the task needs to use the continuation. If the first task you call ConfigureAwait on has already completed, the code will continue to execute synchronously - so at that point, the second ConfigureAwait is important.
Example:
using System;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main()
{
var form = new Form();
form.Load += async (sender, args) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.FromResult(10).ConfigureAwait(false);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000).ConfigureAwait(false);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
};
Application.Run(form);
}
}
Sample output:
1
1
5
So the second Console.WriteLine showed that the code was still running on the same thread despite the ConfigureAwait(false), because Task.FromResult returns an already-completed task.
Introduction
Just out of curiosity, how can I make a multi threading loop where the order is guaranteed from low to high and Console.WriteLine("Done"); has been executed after the loop has done. I've tried three cases explained below.
Case one: Parallel.For(...)
If you will make a for loop that runs parallel in C#, you can use this code:
ParallelLoopResult result = Parallel.For(0, 10, i =>
{
Console.WriteLine($"{i}, task: {Task.CurrentId}, Thread: {Thread.CurrentThread.ManagedThreadId}";
Thread.Sleep(10);
}
Console.WriteLine($"Is completed: {result.IsCompleted}";
This will give next output where the order is not guaranteed. You will see different results if you run the code once more. The run of the program has the order 0-2-4-6-8-... with five tasks and six threads.
0, task: 1, thread: 1
2, task: 2, thread: 3
4, task: 3, thread: 4
6, task: 4, thread: 5
8, task: 5, thread: 6
5, task: 3, thread: 4
7, task: 4, thread: 5
9, task: 5, thread: 6
3, task: 2, thread: 3
1, task: 1, thread: 1
Is completed: True
Case two: the Thread class
I've also tried to use threading instead of the Parallel class. Here is the code:
public static void Main(string[] args)
{
for (int i = 0; i < number; i++)
{
Thread tr = new Thread(() => Print(i));
tr.IsBackground = true;
tr.Start();
}
Console.WriteLine("Done");
}
private static void Print(int i)
{
Console.WriteLine(i);
Thread.Sleep(10);
}
Following result of this code is now that the order isn't also guaranteed form low to high and the string Done has been written after the for loop end but not always guaranteed, however I've place thread.Start(); after Console.WriteLine("Done");.
1
2
3
5
7
7
8
9
9
Done
Like in my second run:
2
3
3
4
5
6
7
8
Done
10
Case tree: async and await
I'll also try this way, but I didn't know how I can implement this way of threading for a loop.
Question
In all the cases I haven't the result I needed. In the first case was it not guaranteed to be ordered and in the second case has Done been written before the loop has run. So my question is how can I run a for loop where the order is always guaranteed and Done written after the loop has run?
You're asking how to make a multithreaded loop where the order of execution is guaranteed. As has been mentioned you can't. However, if you want to order the output, that can be done. Here you've two options
Save the results until they are all complete (see pseudocode below):
Create a dictionary of inputs to outputs
Create a multithreaded loop to process all the inputs and record the outputs
Once they are all complete, write the outputs (in order of inputs) to the screen
Order the outputs as they are complete. This is more difficult than #1, but allows you to show results faster.
Create a multithreaded loop to process all the inputs
Once each thread is complete, show its output, but don't just write it to the screen, insert it into the appropriate spot among all the sorted outputs.
Although you shouldn't use Threads for such sequential uses. What you're asking for is possible.
Here's my example of what you're trying to achieve. It uses multiple thread objects and is guaranteed order. However, you'd probably get better performance just doing it sequentially.
public static void PrintDone()
{
Console.WriteLine("Done");
}
public static void Print(int i)
{
Console.WriteLine(i);
Thread.Sleep(10);
}
static void Main(string[] args)
{
List<Thread> threads = new List<Thread>();
for(int i = 0; i < 10; ++i)
{
int numCopy = i;
Thread th = new Thread(() => Print(numCopy));
threads.Add(th);
}
for (int i = 0; i < 10; ++i)
{
threads[i].Start();
threads[i].Join();
}
PrintDone();
Console.ReadLine();
}
So the gist is to create a bunch of threads, then start them all sequentially (there's no way around that part really), and join the main thread directly after. What'll happen is the main thread will start a "subthread" and then wait for it to finish, once it's finished it'll start the next thread, and repeat until it's out of threads in the list.
However, if you're trying to parallelize the printing of the numbers and guarantee the output's order, you're out of luck. Still possible, but the overhead you'll get for trying to maintain the order will defeat the purpose of the parallelization.
Here's an truly parallel version of the code:
public static void PrintDone()
{
Console.WriteLine("Done");
}
public static void Print(int i, int[] threadStatus)
{
if(i != 0)
{
while(threadStatus[i-1] < 0)
{
Thread.Sleep(10);
}
}
Thread.Sleep(100);
threadStatus[i] = i;
Console.WriteLine(i);
}
static void Main(string[] args)
{
int[] threadStatus = Enumerable.Repeat(-1, 10).ToArray();
List<Thread> threads = new List<Thread>();
for(int i = 0; i < 10; ++i)
{
int numCopy = i;
Thread th = new Thread(() => Print(numCopy, threadStatus));
threads.Add(th);
}
for (int i = 0; i < 10; ++i)
{
threads[i].Start();
}
threads[9].Join();
PrintDone();
Console.ReadLine();
}
Since each thread can only write to one part of the int array and reading is atomic, we can use the int array to keep status on all the threads currently running.
This basically means that in any particular "print" thread you can check to see if they are ready to print within the thread, if not you tell them to sleep in a loop so they periodically check their status.
In my code below, the Id property of ThreadClass is not set deterministically as expected (ThreadArray[0]'s ThreadClass.Id = 0, ThreadArray[1]'s ThreadClass.Id = 1, etc).
If I debug and slow down the Thread.Start()'s, everything works as expected. But when the program runs at full-speed, I get all Id's = 4 (or similar). I can't lock i because it's not a reference variable. Clearly, I am encountering a race condition. What am I doing wrong?
Main.cs
for (int i = 0; i < ThreadCount; i++)
{
ThreadArray[i] = new Thread(() =>
{
new ThreadClass(i);
});
ThreadArray[i].Start();
}
ThreadClass.cs
private int Id { get; set; }
public ThreadClass(int i) {
Id = id;
while(true)
{
Console.WriteLine("I am thread " + i");
Thread.Sleep(5000);
}
}
Expected output:
I am thread 0
I am thread 1
I am thread 2
I am thread 3
... 5 second wait ...
I am thread 0
I am thread 1
I am thread 2
I am thread 3
Actual output:
I am thread 4
I am thread 4
I am thread 4
I am thread 4
... 5 second wait ...
I am thread 4
I am thread 4
I am thread 4
I am thread 4
Note that at this point each instance of ThreadArray is initialized to a valid Thread object.
You're using a version of C# that doesn't close over a fresh copy of the i variable. By the time the threads are executed, i is at or near ThreadCount. Simply create a copy of the variable so the closure can capture that instead:
for (int i = 0; i < ThreadCount; i++)
{
int temp = i;
ThreadArray[i] = new Thread(() =>
{
new ThreadClass(temp);
});
}
By the way, the version of C# in VS 2012 (or .NET 4.5) fixes this. See http://msdn.microsoft.com/en-us/library/hh678682(v=vs.110).aspx
Move your ThreadArray[i].Start() outside your for loop and simply set up all your classes before starting the threads. Even though you will have to loop twice, it should ensure that everything occurs in the order/state that you want it to.
--EDIT Darnit got to the answer just before I did-- :)
let's say we have some simple code like this :
private static void Main()
{
Console.WriteLine("Main thread {0}\n", Thread.CurrentThread.ManagedThreadId);
Action asyncCaller1 = () => LongPerfomingTask(5);
Action asyncCaller2 = () => LongPerfomingTask(3);
var asyncResult1 = asyncCaller1.BeginInvoke(null, null);
var asyncResult2 = asyncCaller2.BeginInvoke(null, null);
asyncResult1.AsyncWaitHandle.WaitOne();
asyncResult2.AsyncWaitHandle.WaitOne();
Console.WriteLine("Done");
}
private static void LongPerfomringTask(int seconds)
{
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("Thread {0} finished execution", Thread.CurrentThread.ManagedThreadId);
}
Delegate.BeginInvoke() does not create a thread, It's executing code in a caller's thread when it is in idle state, right?So, why the output of this sample application is like this :
Main thread 1
Thread 4 finished execution
Thread 3 finished execution
Done
No, Delegate.BeginInvoke uses the thread pool. Always. There's no concept of "executing in the caller's thread when it's idle" unless you're thinking of adding tasks to a UI message queue... were you getting confused with Control.BeginInvoke / Dispatcher.BeginInvoke?
In this case you've got a console app - there's no message pumping going on to start with.
#taras.roshko: Here's a resource to boost your understanding of ThreadPool:
Chapter on Threading