I've been working on a custom multi-threaded server that uses HTTP to communicate with clients. To create new threads, I've been using the Task.Factory.StartNew() method. For synchronization, I've been using ManualResetEvent objects.
Here's the essence of the code:
namespace ThreadTest {
class Program {
private readonly ManualResetEvent _event = new ManualResetEvent(false);
public void Start() {
for (int i = 0; i < 100; i++) {
int num = i;
Task.Factory.StartNew(() => {
Console.WriteLine("Task {0} Started", num);
_event.WaitOne();
});
}
}
static void Main(string[] args) {
var test = new Program();
test.Start();
Console.ReadLine();
}
}
}
In the real code, the _event
object would eventually have Set
called on it to release the waiting tasks.
The problem I've run into is that this code works fine on my development machine (which is dual-core with 2 threads per core and using the MS .NET 4 runtime) but does not work on my server (which is single core with 1 thread per core and using the Mono 2.8开发者_如何学Python runtime). The output on my development machine is:
Task 0 Started
Task 1 Started
Task 3 Started
Task 2 Started
Task 4 Started
Task 5 Started
...
While the server output is
Task 53 Started
My question is: What am I misunderstanding about the ManualResetEvent or Tasks? Why does the TaskFactory continue to make tasks on the dual-core but not the single-core?
Update:
I just tried it on my dual-core (1 thread per core) mac laptop and I got the output
Task 97 Started
Task 1 Started
And then nothing. I also tried it with Mono on my development machine (4 threads) and got:
Task 99 Started
Task 2 Started
Task 98 Started
Task 0 Started
So it looks like a bug with Mono.
Turns out it was a bug in Mono. I filed a report and it's now been fixed.
Your code as presented will never complete any of the tasks as the event is never signaled. Ultimately it runs out of threads to allocate and it locks up. The issue really is "how many threads does the task parallel library spin up under different CPU configurations when none of the threads can proceed" since that's what your code effectively measures.
The Task Parallel Library's default scheduler is based on ThreadPool
, which uses a hill-climbing algorithm to adjust to the number of threads to maximize work item completion rate. The algorithm takes into account how many cores you have.
There are better ways to use the Task Parallel Library to schedule work to happen once a Task has finished, ways that don't tie up threads, e.g ContinueWith
. What are you trying to achieve with the event construct?
精彩评论