While reading up on multi-threading in C# (both from MSDocs, and books like Concurrency in C# by Stephen Cleary), I have repeatedly come across advice that essentially boils down to: threads are older, low-level, abstractions for concurrency that are superseded by Task
and Task<T>
classes.
Now I understand that tasks are higher level, more feature rich and powerful, and can do almost anything that threads were previously used for like asynchrony and parallelism.
My question is: Is there anything that threads can do , that newer Task
and Task<T>
etc. cannot do so that I spend time learning multi-threading just in case I come across those use cases?
CodePudding user response:
Tasks are nice for all the reasons you've mentioned, and they can reuse threads from a pool. This avoids the overhead of having lots of threads (each one needs a stack, and some control structures in the kernel, tracking them and so on) and also avoids the overhead of task switching - it takes some cycles for the kernel to transition between threads. If you have lots of threads competing for the same CPU then you'll spend more time switching and less time doing actual work.
As per one of the comments to your question using Threads directly means you can control the life cycle, the only other thing I can think of is Thread Local Storage (https://docs.microsoft.com/en-us/dotnet/standard/threading/thread-local-storage-thread-relative-static-fields-and-data-slots).
CodePudding user response:
Yes, you need to learn about threads too. Here is a non-exhaustive list of things that you won't be able to do, if you know nothing about multithreading:
- You won't be able to synchronize the actions of your tasks, when these tasks are running in parallel to each other. By knowing nothing about
lock
s,SemaphoreSlim
s,Mutex
es,Barrier
s,Countdown
s etc, your parallel and unsynchronized tasks are going to corrupt the non-thread-safe state of your application. - You won't be able to do atomic mutations of variables and fields, that are used by your tasks, by utilizing the
Interlocked
class. - You won't be able to prevent the compiler from reordering the instructions of your program, resulting to your tasks encountering invalid state, because you'll know nothing about memory barriers, the
volatile
keyword and theVolatile
class. - You won't be able to start a
Task
that runs on an STA thread. - You won't be able to start a
Task
that runs on a foreground thread. - You won't be able to start a
Task
that runs on a thread that hasThreadPriority
other thanNormal
. - You won't be able to utilize an efficient pool of objects, where each thread can use its own dedicated object (
ThreadLocal<T>
).
For learning multithreading, here is a free online resource: Threading in C# by Joseph Albahari.