It's best to be concerned with multithreading
- If it's absolutely necessary to start a separate thread for performance/UI reasons
- If your code may be running in a multithreaded environment (like a web site) and you need to know that it won't break when multiple threads operate on the same class or same values.
But exercise extreme caution. Incorrect use/handling of multiple threads can cause your code to behave unpredictably and inconsistently. Something will work most of the time and then not work for no apparent reason. Bugs will be difficult to reproduce and identify.
That being said, one of the essential concepts of handling multithreading is to ensure that two threads don't try to update the same value at the same time. They can corrupt or partially modify values in ways that would be impossible for a single thread.
One way to accomplish this is with locking.
private object _lockObject = new Object();
private string _myString;
void SetStringValue(string newValue)
{
lock(_lockObject)
{
_myString = newValue;
}
}
You generally have an object that exists only to serve as a lock. When one thread enters that lock
block it acquires a lock on the object. If another thread already has a lock on that object then the next thread just waits for the previous thread to release the lock. That ensures that two threads can't update the value at the same time.
You want to keep the amount of code inside the lock
as small as possible so that the lock is released as soon as possible. And be aware that if it gets complicated with multiple locks then two threads can permanently block each other.
For incrementing and updating numbers there are also interlocked operations that handle the locking for you, ensuring that those operations are executed by one thread at a time.
Just for fun I wrote this console app. It takes a sentence, breaks it into words, and then adds each word back onto a new string using multiple threads and outputs the string.
using System;
using System.Threading.Tasks;
namespace FunWithThreading
{
class Program
{
static void Main(string[] args)
{
var sentence =
"I am going to add each of these words to a string "
+ "using multiple threads just to see what happens.";
var words = sentence.Split(' ');
var output = "";
Parallel.ForEach(words, word => output = output + " " + word);
Console.WriteLine(output);
Console.ReadLine();
}
}
}
The first two times I ran it, the output string was exactly what I started with. Great, it works perfectly! Then I got this:
I am going to add of these words to a string using multiple threads just to see what happens. each
Then I ran it 20 more times and couldn't repeat the error. Just imagine the frustration if this was a real application and something unpredictable like this happened even though I tested over and over and over, and then I couldn't get it to happen again.
So the point isn't that multithreading is evil, but just to understand the risks, only introduce it if you need to, and then carefully consider how to prevent threads from interfering with each other.