I'm not understanding what starvation means as this author explains it - multithreading

In objc.io Issue 2 the author talks about the issue of Starvation with reading and writing:
Just when you thought that there are enough problems to think of, a new one comes around the corner. Locking shared resources can result in the readers-writers problem. In many cases, it would be wasteful to restrict reading access to a resource to one access at a time. Therefore, taking a reading lock is allowed as long as there is no writing lock on the resource. In this situation, a thread that is waiting to acquire a write lock can be starved by more read locks occurring in the meantime.
I assume a reading lock is only allowing the thing that locked it access to read the value, while all others are not able to access it? I understand that you could only read lock if there's no write lock (as the value might be changing), but in the way it uses therefore it seems to imply that "read locks are only allowed if there's no write locks" is used as a means of efficiency/not being wasteful. What does taking a reading lock have to do with being wasteful?
Also, could anyone explain what the last sentence means? I don't understand what impact the read locks would have, or what the read locks would even be on.

Basically what it means is that a read lock allows other items to read the data at the same time.
So imagine the following scenario.
A takes a read lock and starts reading.
Then X comes along and tries to take a write lock, but can't, because it's already locked.
Meanwhile, before A finishes reading, B comes along and takes a read lock. This is allowed because read locks can be concurrent.
Then, A finishes, but X still can't write, because it's locked by B.
Then, before B finishes, C comes along and takes out a read lock. Etc.

The problem occurs when you have "shared read" and "exclusive write" locks. Multiple "shared read" locks can be applied to the entity at the same time, and they will prevent any "exclusive write" lock from gaining access.
"Starvation" occurs when new "shared read" locks keep arriving, before all existing ones are released. This can hold off an "exclusive write" lock indefinitely.
There are several strategies for handling this, such as preventing any new "shared read" lock from being applied if there is an "exclusive write" lock waiting.

1) If only a single read lock were allowed on a shared resource, it would be "wasteful" because any threads which only wanted to read the shared resource would have to queue up and read the resource one at a time.
2) A read lock will not prevent other threads from taking out a read lock, but would prevent other threads from taking write locks.
3) As you can't write lock a shared resource which has one or more read locks on it, the starvation thing would occur if several threads where continually requesting read locks (imagine them in an overlapping fashion); the thread which wanted the write lock would never be able to take it as there would always be a read lock.

Related

What does a mutex lock?

In every tutorial about mutex, mutex is described as a way to prevent for example multiple threads to access the same resources at the same time. But what are those resources. I know that the resources can be a lot of things, like for example variables, but how do i define those variables that shouldnt be used at the same time by another thread? How does Mutex know which variables to "lock"? I dont understand how the compiler can know before executing the code what Mutex should lock between the functions mutex.lock and mutex.release.
The answer depends on how you want to think about it.
At a low level, a mutex locks nothing but itself. Two threads will never be allowed to lock the same mutex at the same time. End of story.
At a higher level, a mutex locks whatever data you want to lock with it. A mutex is a type of advisory lock. It's like a sign hanging on a door knob that says, "in-use, do not enter." It will keep out whoever respects the sign, but it has no actual power to keep anybody out.
If you have some data shared by several threads, and if you don't want any two threads to ever access* the data at the same time, then you can set up a mutex, and declare that, "None shall access these data unless they have the mutex locked." That declaration is what #Wyck called a "protocol" in a comment, above.
It's up to you to ensure that no thread in your program ever accesses the data without holding the mutex locked. I.e., it's up to you to ensure that your code obeys the protocol.
Also note! Nowhere did I mention "method" or "function." There's never any inherent benefit to locking a method or a function. It's always about the data that the method or the function accesses.
* "Access" doesn't just mean "update." If one thread merely tries to read the data while some other thread is in the middle of updating it, the reading thread could see an inconsistent or invalid snapshot of the data, and it could make arbitrarily bad decisions based on what it saw. The consequences could be fatal to the process, or worse.

Can a thread be context-switched while holding a lock?

How do you take care of context-switching when a thread holds a lock and hence blocks other threads? I would expect it's a very common issue.
On a pre-emptive multi-tasking system, you can't prevent yourself from being switched out while holding a lock. But since anything else that's waiting on the lock (assuming that it's not a spinlock) can't be switched in, this is normally not a problem.
Using a spinlock is almost always a bad idea. There are legitimate cases where things can go badly if you hold a lock too long; you can manage this by ensuring that you hold the lock for the least amount of time possible and that you don't do anything that can block while holding it.
The blocked threads don't run, and eventually the thread holding the lock becomes active again, eventually releasing the lock. You don't have to do anything special beyond the usual nitpicky care needed with multithreaded code.

When should I use Shared Locking (Read Locking)

Can someone explain when shared locks should be used. If I understand correctly, shared locks are used when reading and exclusive locks are used while writing.
But why can't I just wait while a mutex is locked when doing a read.
It is for improving performance. Multiple concurrent reads then won't have to happen sequentially, which may be a great bonus if the structure is read frequently. (But still the data read will be consistent and up to date.)
But why can't I just wait while a mutex is locked when doing a read.
Usually for speed. Shared locks allow multiple readers, as the content is not changing. Exclusive lock allows only a single (typically) write operation as you want all the writes to be atomic.
More technical definitions from here.
Exclusive locks protect updates to file resources, both recoverable
and non-recoverable. They can be owned by only one transaction at a
time. Any transaction that requires an exclusive lock must wait if
another task currently owns an exclusive lock or a shared lock against
the requested resource. Shared locks
Shared locks support read integrity. They ensure that a record is not
in the process of being updated during a read-only request. Shared
locks can also be used to prevent updates of a record between the time
that a record is read and the next syncpoint.
A shared locks (also known as read locks) prohibits any other process from requesting a write lock on the specified part of the file. However, other processes can request read locks and keep reading from the resource.
An exclusive lock (also known as write lock) gives a process an exclusive access for writing to the specified part of the file and will prevent any other process to acquire any kind of locking to the resource until the exclusive lock is released.
So a read lock says "you can read now but if you want to write you'll have to wait" whereas a write lock says "you'll have to wait".
For an official description, check out the official locks documentation of GNU C library.
In addition, in many cases, the context of shared/exclusive locking is pessimistic/optimistic locking which is a methodology used to handle multi-users read/write to the same resource. Here is an explanation of the methodology.
But why can't I just wait while a mutex is locked when doing a read.
Because that would be inefficient in certain scenarios, specifically those where a lot of threads are reading a data structure often, but very few are writing and not very often. Since multiple concurrent reads are thread-safe if no one is writing, it would be a waste to have mutual exclusion for the readers.
Imagine a server and multiple clients doing various transactions on some shared data. If most of these clients are simply asking for information, but not changing anything, the server would have horrible performance if it only allowed one client to read at a time.

Is a lock (threading) atomic?

This may sound like a stupid question, but if one locks a resource in a multi-threaded app, then the operation that happens on the resource, is that done atomically?
I.E.: can the processor be interrupted or can a context switch occur while that resource has a lock on it? If it does, then nothing else can access this resource until it's scheduled back in to finish off it's process. Sounds like an expensive operation.
The processor can very definitely still switch to another thread, yes. Indeed, in most modern computers there can be multiple threads running simultaneously anyway. The locking just makes sure that no other thread can acquire the same lock, so you can make sure that an operation on that resource is atomic in terms of that resource. Code using other resources can operate completely independently.
You should usually lock for short operations wherever possible. You can also choose the granularity of locks... for example, if you have two independent variables in a shared object, you could use two separate locks to protect access to those variables. That will potentially provide better concurrency - but at the same time, more locks means more complexity and more potential for deadlock. There's always a balancing act when it comes to concurrency.
You're exactly right. That's one reason why it's so important to lock for short period of time. However, this isn't as bad as it sounds because no other thread that's waiting on the lock will get scheduled until the thread holding the lock releases it.
Yes, a context switch can definitely occur.
This is exactly why when accessing a shared resource it is important to lock it from another thread as well. When thread A has the lock, thread B cannot access the code locked.
For example if two threads run the following code:
1. lock(l);
2. -- change shared resource S here --
3. unlock(l);
A context switch can occur after step 1, but the other thread cannot hold the lock at that time, and therefore, cannot change the shared resource. If access to the shared resource on one of the threads is done without a lock - bad things can happen!
Regarding the wastefulness, yes, it is a wasteful method. This is why there are methods that try to avoid locks altogether. These methods are called lock-free, and some of them are based on strong locking services such as CAS (Compare-And-Swap) or others.
No, it's not really expensive. There are typically only two possibilities:
1) The system has other things it can do: In this case, the system is still doing useful work with all available cores.
2) The system doesn't have anything else to do: In this case, the thread that holds the lock will be scheduled. A sane system won't leave a core unused while there's a ready-to-run thread that's not scheduled.
So, how can it be expensive? If there's nothing else for the system to do that doesn't require acquiring that lock (or not enough other things to occupy all cores) and the thread holding the lock is not ready-to-run. So that's the case you have to avoid, and the context switch or pre-empt issue doesn't matter (since the thread would be ready-to-run).

Do I need to lock object when reading from it?

I am writing a program where there is an object shared by multiple threads:
A) Multiple write threads write to the object (all running the same
function)
B) A read thread which accesses the object every 5 seconds
C) A read thread which accesses the object there is a user request
It is obviously necessary to lock the object when writing to it, as we do not want multiple threads to write to the object at the same time.
My questions are:
Is it also necessary to lock the object when reading from it?
Am I correct to think that if we just lock the object when writing, a critical section is enough; but if we lock the object when reading or writing, a mutex is necessary?
I am asking this question because in Microsoft Office, it is not possible for two instances of Word to access a document in read/write access mode; but while the document is being opened in read/write mode, it is possible to open another instance of Word to access the document in read only mode. Would the same logic apply in threading?
As Ofir already wrote - if you try to read data from an object that some other thread is modyfying - you could get data in some inconsistent state.
But - if you are sure the object is not being modified, you can of course read it from multiple threads. In general, the question you are asking is more or less the Readers-writers problem - see http://en.wikipedia.org/wiki/Readers-writers_problem
Lastly - a critical section is an abstract term and can be implemented using a mutex or a monitor. The syntax sugar for a critical section in java or C# (synchronized, lock) use a monitor under the covers.
Is it also necessary to lock the object when reading from it?
If something else could write to it at the same time - yes. If only another read could occur - no. In your circumstances, I would say - yes.
Am I correct to think that if we just lock the object when writing, a
critical section is enough; but if we
lock the object when reading or
writing, a mutex is necessary?
No, you can use a critical section for both, other things being equal. Mutexes have added features over sections (named mutexes can be used from multiple processes, for example), but I don't think you need such features here.
It is necessary, because otherwise (unless operations are atomic) you may be reading an intermediate state.
You may want to allow multiple readers at the same time which requires a (bit) more complex kind of lock.
depends on how you use and read it. if your read is atomic (i.e, won't be interrupted by write) and the read thread does not have dependency with the write threads, then you maybe able to skip read lock. But if your 'read' operation takes some time and takes heavy object interation, then you should lock it for read.
if your reading does not take a very long time (i.e., won't delay the write threads too long), critical section should be enough.
locking is only needed when two processes can change the same database table elements.
when you want to read data it is always secure. you read data of a consistent database. the process changing the data has a shadow version which is consistent and will override current data when you save it. but if you are running a reading process which is depending on critical value from database elements you should look for locks which indicates those values are likely to be altered. so your reading is delayed until the lock is gone.

Resources