The problem here is that all your callers are using a different mutex; you need the locking object to be shared, usually by making it a field. For example, and switching to a simpler lock
metaphor:
private readonly object syncLock = new object();
public void ThreadSafeMethod() {
lock(syncLock) {
/* critical code */
}
}
or using the mutex:
private readonly Mutex m = new Mutex();
public void ThreadSafeMethod() {
m.WaitOne();
try {
/* critical code */
} finally {
m.ReleaseMutex();
}
}