Kevin McGuire wrote:I can not understand (0.9 * 5). Why are you taking a percent?
The word I would use to describe the 0.9 and 0.1 in Brendan's equation is "probability".
No. It is a lock. Just not a spinlock.
I was replying specifically to this part of your explanation:
When migrating a thread you do a test and set (xchg) on a field in each processor's thread container (at the worst case scenario). I said test and set not sit and spin. If you test and set with success then you add a entry for this thread to another field.
This "test and set" sequence, also known as "compare-and-swap", is the building block of all lock-free techniques for atomically updating shared memory. I realize that your intention was to show how to implement mutexes or semaphores using this technique, which I hadn't considered before. To me, these two things exist at different levels of abstraction. At a high level, you've implemented a kind of lock (not a spinlock, I agree). At the low level, where you're managing concurrent access to the queue that represents that lock, you're using compare-and-swap, which is a lock-free technique. I hope this clears up the terminology.
That was my entire point from the beginning. You do not call everything a spinlock since it is quite confusing when people read that..
What you described is definitely not a spinlock, I agree. I was not claiming that it was. I was ignoring mutexes and semaphores however, because 1) all the implementations of mutexes and semaphores that I'd seen so far rely on spinlocks (but as you pointed out, this is not the only way to do it), and 2) Like Brendan, I believe it is impractical to use locks that block the acquiring thread in performance-sensitive parts of a kernel, like a memory manager.
Quote: "You always need spinlocks in the implementation of an OS' memory manager, unless someone very clever can think of lock-free algorithms for everything (which I doubt is possible)."
(spinlock || lockfree)
No. Take for instance a uniprocessor which could completely disable interrupts.
I mentioned that already too:
At the lowest level of implementation, there are shared data structures, and you have to protect them from concurrent access. Fundamentally, there are only three ways to do this -- disable interrupts (which only works on a uniprocessor machine), use a lock-free algorithm (for something simple like a queue, this is feasible, but is not going to be feasible in the general case), or use a spinlock. All higher-level abstractions for safe concurrent access to shared data are built up from these primitives.
How many uniprocessor machines do you think will be in widespread use in 3-5 years? Even the QNX real-time OS is designed for use with SMP, so it's not just in desktops and servers where uniprocessors are disappearing. In other words, I don't think it's practical anymore to rely on disabling interrupts.
I will specifically note that you spoke of a memory manager not a transactional memory implementation. I think this was confusing and wrong.
The discussion started (wayyyy back) with Brendan proposing STM implemented in the OS' memory manager. The paper on XTM also discussed this technique. Page-based STM involves managing transaction read and write sets via the paging mechanism, so it makes sense to make it part of the MM. That's why I've been discussing locking in the MM -- because Brendan was talking about OS-level STM support when he mentioned using a spinlock.
There are locks other than a spinlock -- the word used was not concise enough and would be confusing to someone reading your post.
True, there are locks other than a spinlock. From my point of view, spinlocks and other types of locks exist at different levels of abstraction, as I explained above. I'll try to elaborate further.
I think the easiest way to make the distinction is to consider which part of a thread's execution you think of as the "critical section". Consider a mutex implemented as a queue of waiting threads protected by a spinlock. Imagine that a user-mode thread wants to enter a critical section because it's going to access memory in its process' address space that is shared with other threads of that process. From that thread's point of view, the mutex is the lock.
Now look at it from the kernel's point of view. When the user-mode thread makes the "Mutex_lock" system call, it's now kernel code that is running on that thread. That kernel code needs to access a data structure (the waiting thread queue of the mutex) that is shared by potentially all threads in the system, since it is in the kernel's address space. So from the kernel's point of view, its own implementation of "Mutex_lock" is another critical section. In this example, the kernel protects that critical section with a spin-lock. It could use "compare-and-swap" techniques instead, as you say.
This is what I mean by different locks being at different levels of abstraction. The mutex is a lock, but it is not a primitive mechanism -- it is further composed of other mechanisms (queue of waiting threads plus a means to protect it).