also review http://www.yoda.arachsys.com/csharp/threads/alternative.shtml his note
The lock statement automatically takes a copy of the reference you specify, and calls both Enter and Exit with it. (In the example above, and everywhere else in this article, variables used to hold locks are declared as read-only. I have yet to come across a good reason to change what a particular piece of code locks on.)
Lock MSDN: ensures that one thread does not enter a critical section of code while another thread is in the critical section. If another thread attempts to enter a locked code, it will wait, block, until the object is released.

using System;
using System.Threading;
//csc thread_enter_exit_lock.cs
public class Test
{
//public static int n = 0;
static readonly object countLock = new object();
public static int n = 0;
//public string str = "";
static void Main()
{
Console.Write("Enter sleep time: ");
string str = Console.ReadLine();
if (str!="") { n = int.Parse(str); } else { n = 0 ;}
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();

for (int i=0; i < 3; i++)
{
lock(countLock) {

Thread.Sleep(n);
Console.WriteLine ("Start--caller--Primary---" + i);
Monitor.Enter(countLock);

Console.WriteLine("Thread: {0} in caller : ", Thread.CurrentThread.GetHashCode());
Console.WriteLine ("cycle count={0}", i);
Console.WriteLine ("Exit--caller-primary---{0}", i);
Monitor.Exit(countLock);
}

}
Console.WriteLine ("--caller----- Monitor--Join");
thread.Join();
//Console.WriteLine ("Final count: {0}", n);
Console.ReadLine();
}

static void ThreadJob()
{
for (int i=0; i < 5; i++)
{
Thread.Sleep(n);
Console.WriteLine ("\t\t\tStart Monitor/Lock--Secondary---{0}", i);
Monitor.Enter(countLock);
Console.WriteLine("\t\t\tThread: {0} in second : ", Thread.CurrentThread.GetHashCode());
Console.WriteLine ("\t\t\t\t delgated count={0}", i);
Console.WriteLine ("\t\t\tExit--Secondary---{0}", i);
Monitor.Exit(countLock);
// Thread.Sleep(40);
}
}
}
 

The command line compiler complained around the keyword "lock"; when sleep was zeroed, became disorganized call.
With sleep time = 5 we got

which was very similar to

 
Now there is no sleep time for caller

using System;
using System.Threading;
//csc thread_enter_exit_lock_2.cs
public class Test
{
//public static int n = 0;
static readonly object countLock = new object();
public static int n = 0;
//public string str = "";
static void Main()
{
Console.Write("Enter sleep time: ");
string str = Console.ReadLine();
if (str!="") { n = int.Parse(str); } else { n = 0 ;}
ThreadStart job = new ThreadStart(ThreadJob);
Thread thread = new Thread(job);
thread.Start();
//Thread.Sleep(n);
for (int i=0; i < 3; i++)
{
Console.WriteLine ("Start--caller--Primary---" + i);
Monitor.Enter(countLock);
lock(countLock);
Console.WriteLine ("cycle count={0}", i);
Console.WriteLine ("Exit--caller-primary---{0}", i);
Monitor.Exit(countLock);

}
Console.WriteLine ("--caller----- Monitor--Join");
thread.Join();
//Console.WriteLine ("Final count: {0}", n);
Console.ReadLine();
}

static void ThreadJob()
{
for (int i=0; i < 5; i++)
{
Thread.Sleep(n);
Console.WriteLine ("\t\t\tStart Monitor/Lock--Secondary---{0}", i);
Monitor.Enter(countLock);
Console.WriteLine ("\t\t\t\t2ndcycle count={0}", i);
Console.WriteLine ("\t\t\tExit--Secondary---{0}", i);
Monitor.Exit(countLock);
// Thread.Sleep(40);
}
}
}