Q:

Why lock("myLock") can cause problems?

I have read the following in the Microsoft's C# Reference:

lock("myLock") is a problem because any other code in the process
  using the same string, will share the same lock.

What does it mean exactly?
Is the following code not working as I expect? (I expect that ReadyCount is consistent)
public class Calculator
{
    public int ReadyCount { get; private set; }

    public void IncreaseReadyCount()
    {
        lock ("ReadyCount")
        {
            ReadyCount++;
        }
    }

    public void Calculate()
    {
        Parallel.ForEach(list, litItem =>
        {
            IncreaseReadyCount();
        });
    }
}

A:

The question is: what is the scope of that lock? you can't tell; it is at least equivalent to static/global to your Calculator type, but it could also be coincidentally shared by any other code anywhere that happens to do a ldstr 'ReadyCount' (which gives back the interned version) and lock on it (or use Monitor, etc). Unlikely, but a risk.
More to the point, it just isn't obvious to the casual reader, which is a problem. If you intended it to be a static/global lock, then this is equivalent to your code, but more obvious and without the risk of unrelated code taking the lock by chance:
static readonly object readyCountLock = new object();
...
lock(readyCountLock) {...}

With this, at least it is obvious what it is doing.

Personally, though, I'd be tempted to just use Interlocked.Increment(ref _someField) :)

A:

In addition to what Marc said, in real life people ofren try to lock on strings that might not be interned, such as locking on some key from the database record. Locking on strings only (kind of) works if you lock on interned string. But consider this:
// not interned, but both strings represent "test"
string lock1 = new string(new char[] { 't', 'e', 's', 't' });
string lock2 = new string(new char[] { 't', 'e', 's', 't' });
Task.Run(() =>
{
    lock (lock1) {
        Console.WriteLine("1 entered");     
        Thread.Sleep(1000);
    }
});
Task.Run(() =>
{
    lock (lock2)
    {
        Console.WriteLine("2 entered");
        Thread.Sleep(1000);
    }
});

This code immediately executes both "protected" sections, because despite of both strings are "test" - they are different instances. So locking on constant string is danregrous because it's global and you never know which else code uses such "lock", and locking on string variable is dangerous because it might just not work at all.
To answer a comment about locking on ReadyCount.ToString(). That's exactly how people try to do this in real life (where ReadyCount is some property of database record or similar). I guess by ReadyCount you mean some number, not really a string (otherwise calling ToString makes no sense). And no, this is also bad, because:
int readyCount = 1;
string lock1 = readyCount.ToString();
string lock2 = readyCount.ToString();
bool same = Object.ReferenceEquals(lock1, lock2);
// nope, not the same, lock will not work

