What is the meanig of P() and V() operation in semaphore being atomic in nature? What does the the term atomic mean here? - operating-system

I am studying operating systems. I am reading about critrical section problem and i came accross semaphore. There are two operations p() also known as down operation and v() operation which is also known as up operation.
Its written that p() and v() are atomic in nature. What is the meaning of being atomic.

Atomic simply means that whatever happens in this operation: It will fail completely and steps until failing will be reverted in some kind or end successfully. No steps in between are possible.
In context of semaphores we are talking about e.g. sharing resources between different consumers. Consumer A and B want to access a shared resource, e.g. a list containing data objects. The access on this list would be atomic if the list access is blocked while A accesses the list, so B needs to wait until A is done with the list and finished it's atomic operation.
It would be bad if the operation on the list would not be atomic: The list is blocked while A is working on it and suddenly something happens, so A simply dies, leaving the list blocked. B would wait forever, since the list access will not be unblocked. This is a classic deadlock scenario.

Related

How Resource Allocation Graph Algorithm can prevent deadlocks?

According to Operating System Concepts book, Resource-Allocation-Graph Algorithm can prevent deadlocks as follow:
If we have the following allocation graph
https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/images/Chapter7/7_07_DeadlockAvoidance.jpg
And P1 tried to allocate resource R2, the system prevents it and makes it wait, because that will lead to an unsafe state.
My question is as shown from the graph, P2 is waiting for P1 to release R1, and P1 is now waiting to allocate R2 and that leads to a deadlock. How this algorithm can prevent this type of deadlocks ?
I don't have a copy of your book, but I suspect a typo. The idea is to return an error (EDEADLOCK) to the resource allocation request that would complete the cycle; thus detecting pending deadlock rather than actively avoiding it. It is still up to the process with the failed request to take some corrective action, like dropping all its resources and trying to re-acquire them.
If you replace resources with semaphore or mutex, it should be clear that waiting isn't going to help anything.
To actively avoid deadlock, you pretty much need to either use semaphore sets -- that is acquire all the locks that a particular code path will need in one place (see system V semaphores) -- or arrange your code to use a particular ordering of locks. An example of the latter is to allocate locks by increasing address, thus all actors will attempt the allocation in the same order. Neither is practical for finely grained general purpose code, but possible for transaction processing applications.

How can (messaging) queue be scalable?

I frequently see queues in software architecture, especially those called "scalable" with prominent representative of Actor from Akka.io multi-actor platform. However, how can queue be scalable, if we have to synchronize placing messages in queue (and therefore operate in single thread vs multi thread) and again synchronize taking out messages from queue (to assure, that message it taken exactly once)? It get's even more complicated, when those messages can change state of (actor) system - in this case even after taking out message from queue, it cannot be load balanced, but still processed in single thread.
Is it correct, that putting messages in queue must be synchronized?
Is it correct, that putting messages out of queue must be synchronized?
If 1 or 2 is correct, then how is queue scalable? Doesn't synchronization to single thread immediately create bottleneck?
How can (actor) system be scalable, if it is statefull?
Does statefull actor/bean mean, that I have to process messages in single thread and in order?
Does statefullness mean, that I have to have single copy of bean/actor per entire system?
If 6 is false, then how do I share this state between instances?
When I am trying to connect my new P2P node to netowrk, I believe I have to have some "server" that will tell me, who are other peers, is that correct? When I am trying to download torrent, I have to connect to tracker - if there is "server" then we do we call it P2P? If this tracker will go down, then I cannot connect to peers, is that correct?
Is synchronization and statefullness destroying scalability?
Is it correct, that putting messages in queue must be synchronized?
Is it correct, that putting messages out of queue must be synchronized?
No.
Assuming we're talking about the synchronized java keyword then that is a reenetrant mutual exclusion lock on the object. Even multiple threads accessing that lock can be fast as long as contention is low. And each object has its own lock so there are many locks, each which only needs to be taken for a short time, i.e. it is fine-grained locking.
But even if it did, queues need not be implemented via mutual exclusion locks. Lock-free and even wait-free queue data structures exist. Which means the mere presence of locks does not automatically imply single-threaded execution.
The rest of your questions should be asked separately because they are not about message queuing.
Of course you are correct in that a single queue is not scalable. The point of the Actor Model is that you can have millions of Actors and therefore distribute the load over millions of queues—if you have so many cores in your cluster. Always remember what Carl Hewitt said:
One Actor is no actor. Actors come in systems.
Each single actor is a fully sequential and single-threaded unit of computation. The whole model is constructed such that it is perfectly suited to describe distribution, though; this means that you create as many actors as you need.

Looking for message bus implementations that offer something between full ACID and nothing

Anyone know of a message bus implementation which offers granular control over consistency guarantees? Full ACID is too slow and no ACID is too wrong.
We're currently using Rhino ESB wrapping MSMQ for our messaging. When using durable, transactional messaging with distributed transactions, MSMQ can block the commit for considerable time while it waits on I/O completion.
Our messages fall into two general categories: business logic and denormalisation. The latter account for a significant percentage of message bus traffic.
Business logic messages require the guarantees of full ACID and MSMQ has proven quite adequate for this.
Denormalisation messages:
MUST be durable.
MUST NOT be processed until after the originating transaction completes.
MAY be processed multiple times.
MAY be processed even if the originating transaction rolls back, as long as 2) is adhered to.
(In some specific cases the durability requirements could probably be relaxed, but identifying and handling those cases as exceptions to the rule adds complexity.)
All denormalisation messages are handled in-process so there is no need for IPC.
If the process is restarted, all transactions may be assumed to have completed (committed or rolled back) and all denormalisation messages not yet processed must be recovered. It is acceptable to replay denormalisation messages which were already processed.
As far as I can tell, messaging systems which deal with transactions tend to offer a choice between full ACID or nothing, and ACID carries a performance penalty. We're seeing calls to TransactionScope#Commit() taking as long as a few hundred milliseconds in some cases depending on the number of messages sent.
Using a non-transactional message queue causes messages to be processed before their originating transaction completes, resulting in consistency problems.
Another part of our system which has similar consistency requirements but lower complexity is already using a custom implementation of something akin to a transaction log, and generalising that for this use case is certainly an option, but I'd rather not implement a low-latency, concurrent, durable, transactional messaging system myself if I don't have to :P
In case anyone's wondering, the reason for requiring durability of denormalisation messages is that detecting desyncs and fixing desyncs can be extremely difficult and extremely expensive respectively. People do notice when something's slightly wrong and a page refresh doesn't fix it, so ignoring desyncs isn't an option.
It's not exactly the answer you're looking for, but Jonathan Oliver has written extensively on how to avoid using distributed transactions in messaging and yet maintain transactional integrity:
http://blog.jonathanoliver.com/2011/04/how-i-avoid-two-phase-commit/
http://blog.jonathanoliver.com/2011/03/removing-2pc-two-phase-commit/
http://blog.jonathanoliver.com/2010/04/idempotency-patterns/
Not sure if this helps you but, hey.
It turns out that MSMQ+SQL+DTC don't even offer the consistency guarantees we need. We previously encountered a problem where messages were being processed before the distributed transaction which queued them had been committed to the database, resulting in out-of-date reads. This is a side-effect of using ReadCommitted isolation to consume the queue, since:
Start transaction A.
Update database table in A.
Queue message in A.
Request commit of A.
Message queue commits A
Start transaction B.
Read message in B.
Read database table in B, using ReadCommitted <- gets pre-A data.
Database commits A.
Our requirement is that B's read of the table block on A's commit, which requires Serializable transactions, which carries a performance penalty.
It looks like the normal thing to do is indeed to implement the necessary constraints and guarantees oneself, even though it sounds like reinventing the wheel.
Anyone got any comments on this?
If you want to do this by hand, here is a reliable approach. It satisfies (1) and (2), and it doesn't even need the liberties that you allow in (3) and (4).
Producer (business logic) starts transaction A.
Insert/update whatever into one or more tables.
Insert a corresponding message into PrivateMessageTable (part of the domain, and unshared, if you will). This is what will be distributed.
Commit transaction A. Producer has now simply and reliably performed its writes including the insertion of a message, or rolled everything back.
Dedicated distributer job queries a batch of unprocessed messages from PrivateMessageTable.
Distributer starts transaction B.
Mark the unprocessed messages as processed, rolling back if the number of rows modified is different than expected (two instances running at the same time?).
Insert a public representation of the messages into PublicMessageTable (a publically exposed table, in whatever way). Assign new, strictly sequential Ids to the public representations. Because only one process is doing these inserts, this can be guaranteed. Note that the table must be on the same host to avoid 2PC.
Commit transaction B. Distributor has now distributed each message to the public table exactly once, with strictly sequantial Ids.
A consumer (there can be several) queries the next batch of messages from PublicMessageTable with Id greater than its own LastSeenId.
Consumer starts transaction C.
Consumer inserts its own representation of the messages into its own table ConsumerMessageTable (thus advancing LastSeenId). Insert-ignore can help protect against multiple instances running. Note that this table can be in a completely different server.
Commit transaction C. Consumer has now consumed each message exactly once, in the same order the messages were made publically available, without ever skipping a message.
We can do whatever we want based on the consumed messages.
Of course, this requires very careful implementation.
It is even suitable for database clusters, as long as there is only a single write node, and both reads and writes perform causality checks. It may well be that having one of these is sufficient, but I'd have to consider the implications more carefully to make that claim.

How to handle concurrent access to a Scala collection?

I have an Actor that - in its very essence - maintains a list of objects. It has three basic operations, an add, update and a remove (where sometimes the remove is called from the add method, but that aside), and works with a single collection. Obviously, that backing list is accessed concurrently, with add and remove calls interleaving each other constantly.
My first version used a ListBuffer, but I read somewhere it's not meant for concurrent access. I haven't gotten concurrent access exceptions, but I did note that finding & removing objects from it does not always work, possibly due to concurrency.
I was halfway rewriting it to use a var List, but removing items from Scala's default immutable List is a bit of a pain - and I doubt it's suitable for concurrent access.
So, basic question: What collection type should I use in a concurrent access situation, and how is it used?
(Perhaps secondary: Is an Actor actually a multithreaded entity, or is that just my wrong conception and does it process messages one at a time in a single thread?)
(Tertiary: In Scala, what collection type is best for inserts and random access (delete / update)?)
Edit: To the kind responders: Excuse my late reply, I'm making a nasty habit out of dumping a question on SO or mailing lists, then moving on to the next problem, forgetting the original one for the moment.
Take a look at the scala.collection.mutable.Synchronized* traits/classes.
The idea is that you mixin the Synchronized traits into regular mutable collections to get synchronized versions of them.
For example:
import scala.collection.mutable._
val syncSet = new HashSet[Int] with SynchronizedSet[Int]
val syncArray = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
You don't need to synchronize the state of the actors. The aim of the actors is to avoid tricky, error prone and hard to debug concurrent programming.
Actor model will ensure that the actor will consume messages one by one and that you will never have two thread consuming message for the same Actor.
Scala's immutable collections are suitable for concurrent usage.
As for actors, a couple of things are guaranteed as explained here the Akka documentation.
the actor send rule: where the send of the message to an actor happens before the receive of the same actor.
the actor subsequent processing rule: where processing of one message happens before processing of the next message by the same actor.
You are not guaranteed that the same thread processes the next message, but you are guaranteed that the current message will finish processing before the next one starts, and also that at any given time, only one thread is executing the receive method.
So that takes care of a given Actor's persistent state. With regard to shared data, the best approach as I understand it is to use immutable data structures and lean on the Actor model as much as possible. That is, "do not communicate by sharing memory; share memory by communicating."
What collection type should I use in a concurrent access situation, and how is it used?
See #hbatista's answer.
Is an Actor actually a multithreaded entity, or is that just my wrong conception and does it process messages one at a time in a single thread
The second (though the thread on which messages are processed may change, so don't store anything in thread-local data). That's how the actor can maintain invariants on its state.

Why semaphore?

Why use binary semaphores when the same functionality can be achieved with a simple variable ?
Because a semaphore isn't a simple variable, it's a larger construct than that.
Specifically, with a counting semaphore (which a binary semaphore is, effectively, with a count of 1), there's the added capability of blocking any process/thread that tries to increment the semaphore above its maximum value.
Semaphores also have the additional facility that their state is changed "atomically", which means that the underlying memory is surrounded by logic to ensure that the CPU caches and such are flushed, and that when the value is changed, it's changed for "everyone". This is particularly important on modern multi-core processors.
The semaphore is appropriate to use when you are trying to guard a shared resource from over use. A binary semaphore is perfect for resources that can only be used by one process/thread at a time.
Because a variable does not work across processes. A system semaphore does.
A number of reasons. Because a semaphore is provided by the operating system, it can...
a) be shared among multiple processes.
b) be used to block processes in waiting, instead of busily waiting.
c) actually work. A variable shared by multiple threads, or in shared memory space for multiple processes, won't give you the safety of a semaphore, because you never know when your thread/process will lose control. When you acquire a binary semaphore, you KNOW you are the only thread/process in that code section, the OS guarantees that.
I recommend you read a book on this, it's kinda a silly question :) no offence!
Semaphores atomic operations are essential to multi-threaded code, otherwise there would be no way to determine which thread went first. For example if you have two threads that process email requests and you want each person to only get one email; you need to determine if an email request has already been processed. Without a semaphore here is what happens:
Thread A checks if email[0] has been read, it has not
Thread B checks if email[0] has been read, it has not
Thread A sends email[0] and marks it as done
Thread B sends email[0] and marks it as done
For the user the email has been sent twice because both threads saw it as not processed. Now with a semaphore here is what happens to the email:
Thread A marks email[0] as in progress via a semaphore
Thread B checks email[0] and sees the semaphore is marked
Thread A sends email[0] and marks it as done then unmarks the semaphore
With the semaphore only one thread will process the email.
Actually, Semaphore is not like a single variable. As explained above it comes with so many advantages. You can read the book, "The Little Book of Semaphores, 2nd Edition,By Allen B. Downey" for more details about semaphores.
A semaphore restricts access across processes, while a variable, even one that is global to your application, cannot do the same system-wide.
Besides, why reinvent the wheel? You'd have to handle all of the implementation yourself with a variable, whereas with a semaphore, the functionality is already provided by the operating system and guaranteed to work.
Lets assume a simple way of implementing a resource protection could be done by using a variable i.e. a BOOLEAN. I'll give an example:
while {resource_protected == TRUE}
{
// resource is protected
}
Now we can protect a resource by setting resource_protected == TRUE.
To check if the resource is available we just use something like this:
if {resource_protected == FALSE}
{ // <---- rescheduling possible here!
resource_protected == TRUE; // protect resource
}
else
{
//try again later
}
But there are two problems with this method. First, this creates a busy wait thus the processor is not free to do other stuff. Second, and more important, this active process can be rescheduled (moved to waiting queue) after it checks the BOOLEAN but before it protects the resource by setting the BOOLEAN to TRUE thus creating the illusion for other processes that the resource is still free, because the BOOLEAN is not yet set. This allows an other process to claim the resource. A now active process (promoted from waiting queue to running due to rescheduling) protects the resource by setting the BOOLEAN to TRUE (because it has not been set by the rescheduled process in the waiting queue). Now this active process is rescheduled and the previous process becomes active again it will set the BOOLEAN to TRUE (although it has been set to TRUE already by the second process) because it has already checked the BOOLEAN. Now both processes claim the same resource and you will die an old man trying to debug this mess.
With semaphores you can avoid this ugly ugly mess because it allows atoms. Atoms are sets of instructions which appear indivisible from the perspective of other processes. Thus avoiding such mishaps through bad rescheduling.