Assume accounts X and Y contain $100 and $200, respectively. Now, consider the simple task of transferring $10 from account X to account Y. It can be decomposed into a withdrawal task and a deposit task (in any order). Further, assume these tasks either succeed or fail, e.g., withdrawal succeeds by taking out $10 from the account or fails to remove any amount from the account.

Transfer(X, Y):
Withdraw(X, 10)
Deposit(Y, 10)

When we say transfer should be atomic, we mean

  1. when transfer succeeds, we should observe that both withdrawal and deposit have succeeded.

Atomicity: ensure either all or none of the sub-tasks succeed.

If you are wondering “what about the case where one of withdrawal or deposit fails and the other succeeds?”, then the above requirement disallows such cases. So, in an atomic system P, such cases will either not be allowed to occur or transformed into one of the above two cases when they occur.

When we say transfer should occur in isolation, we mean the effects of sub-tasks of transfer should be hidden from the rest of the system until the transfer completes. Since it is hard to precisely define the the rest of the system, we often say transfer M should occur in isolation from transfer N, i.e., when transfer N is happening, transfer M should not see the effects of the sub-tasks of transfer N and vice versa.

Isolation: ensures the effects of sub-tasks are hidden until the task completes.

Now consider four possible scenarios.

  1. The transfer is executed neither atomically nor in isolation.
    In this case, if the deposit fails, then $10 would be lost as it was withdrawn from account X but not deposited into account Y. Further, while the transfer is happening, we can observe the amount in account X has decreased by $10. Actions taken depending on this observation (e.g., reporting account X has $90) can be “wrong” despite being based on correct information, e.g., report a decrease in balance with no evidence of transfer.

Note that, atomicity is local property limited to one task while isolation is a non-local property that spans multiple tasks that need to be isolated from each other.

In databases, transactions are used to achieve both atomicity and isolation (as in the above scenarios) and transaction primitives ensure both atomicity and isolation.

In concurrent/parallel programming, we rely on mutual exclusion to only achieve isolation. Unlike with transactions, atomicity is achieved by the actions performed within the mutual exclusion region and not ensured by mutual exclusion primitives (except transactional primitives such as STM).

Written by

Programming, experimenting, writing | Past: SWE, Researcher, Professor | Present: SWE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store