Suppose thread 1 tries to acquire a lock on the lockObj object using the lock(lockObj)
statement, but this object is already locked by thread 2 at the moment thread 1 tries to acquire a lock on it. Thread 1 will block, right?
Now suppose that during this blocking, there is a context switch, because there are other threads and applications waiting to run. Is the elapsed time until thread 1 is on Running state again and able to acquire the lock dependent on the OS timer resolution (Ex: default 15.6 ms on Windows 7)?
If the answer to the above question is YES, then I have another doubt:
It is easy to create a simple program to test the average overhead of Thread.Sleep(1)
using Stopwatch and conclude that it converges to the OS timer resolution (15.6 ms, for instance). But I'm finding it hard to create a program to obtain the same conclusion for a lock statement. Mainly because:
1) It is difficult to ensure that the thread trying to acquire the lock will always block (or at least to know WHEN it has blocked before acquiring the lock);
2) I don't know how to force a context switch whenever the thread trying to acquire the lock blocks. Is there ALWAYS a context switch when the current running thread blocks?
Any help will be appreciated.
Suppose thread 1 tries to acquire a lock on the lockObj object using the lock(lockObj) statement, but this object is already locked by thread 2 at the moment thread 1 tries to acquire a lock on it. Thread 1 will block, right?
Yes.
Now suppose that during this blocking, there is a context switch, because there are other threads and applications waiting to run. Is the elapsed time until thread 1 is on Running state again and able to acquire the lock dependent on the OS timer resolution (Ex: default 15.6 ms on Windows 7)?
Not directly, no. In general, thread 1 will become ready as soon as the wait object it was blocked on becomes signaled. AT THAT TIME, the OS scheduing algorithm will run and thread 1 will be set running on a core if one is free or if its priority is enough to allow it to be included in the set of thread to run on the available cores. It is possible that a timer interrupt my conincidentally arrive and set another high-priority 'thread 3' ready and so prevent thread 1 from running, but that is a along way from saying that 'acquiring the lock is dependent on the OS timer resolution'.
If there is a core free to run thread 1, I have found empirically that it runs ~7us after the signal from thread 2 on my Windows system - a few microseconds, not 15.6 ms or anything like it.
If thread 1 had to wait until the next timer interrupt to run afer some signal, performance would be abysmally bad. There is no need for it to wait - the OS has been entered by the signal from thread 2 and the OS decides what set of threads to run at that time. It may not run thread 1 immediately because all cores are already running higher-priority threads, it may preempt thread 2 because thread 1 has a higher dynamic priority or it may preempt another thread running on another core by issuing a hardware-interrupt to the other core using its interprocessor comms driver. The timer interrupt and the 'quantum' thingy is essentially irrelevant in your scenario.
Try not to fixate on the 'quantum' concept, (which is a stupid name because 'quanta' are supposed to be indivisible and threads rarely run for exact timer-driven intervals because of I/O and inter-thread signaling), and think instead of a state-machine whose inputs are hardware interrupts and system calls, and the output is a set of threads running on cores. The hardware timer interrupt is just one of such inputs that can change the set of running threads.