Lably
Skip to content

Concurrent computing

Executing several computations during overlapping time periods

  • 12 min read
  • 6 chapters

Related on Lably

Through Computing, Computation and Computer program

This is a property of a system—whether a program, computer, or a network—where there is a separate execution point or "thread of control" for each process. A concurrent system is one where a computation can advance without waiting for all other computations to complete.

Concurrent computing is a form of modular programming. In its paradigm an overall computation is factored into subcomputations that may be executed concurrently. Pioneers in the field of concurrent computing include Edsger Dijkstra, Per Brinch Hansen, and C.A.R. Hoare.

Introduction

The concept of concurrent computing is frequently confused with the related but distinct concept of parallel computing, although both can be described as "multiple processes executing during the same period of time". In parallel computing, execution occurs at the same physical instant: for example, on separate processors of a multi-processor machine, with the goal of speeding up computations—parallel computing is impossible on a (one-core) single processor, as only one computation can occur at any instant (during any single clock cycle). By contrast, concurrent computing consists of process lifetimes overlapping, but execution does not happen at the same instant. The goal here is to model processes that happen concurrently, like multiple clients accessing a server at the same time. Structuring software systems as composed of multiple concurrent, communicating parts can be useful for tackling complexity, regardless of whether the parts can be executed in parallel.

For example, concurrent processes can be executed on one core by interleaving the execution steps of each process via time-sharing slices: only one process runs at a time, and if it does not complete during its time slice, it is paused, another process begins or resumes, and then later the original process is resumed. In this way, multiple processes are part-way through execution at a single instant, but only one process is being executed at that instant.

Concurrent computations may be executed in parallel, for example, by assigning each process to a separate processor or processor core, or distributing a computation across a network.

The exact timing of when tasks in a concurrent system are executed depends on the scheduling, and tasks need not always be executed concurrently. For example, given two tasks, T1 and T2:

  • T1 may be executed and finished before T2 or vice versa (serial and sequential)
  • T1 and T2 may be executed alternately (serial and concurrent)
  • T1 and T2 may be executed simultaneously at the same instant of time (parallel and concurrent)

The word "sequential" is used as an antonym for both "concurrent" and "parallel"; when these are explicitly distinguished, concurrent/sequential and parallel/serial are used as opposing pairs. A schedule in which tasks execute one at a time (serially, no parallelism), without interleaving (sequentially, no concurrency: no task begins until the prior task ends) is called a serial schedule. A set of tasks that can be scheduled serially is serializable, which simplifies concurrency control.

Coordinating access to shared resources

The main challenge in designing concurrent programs is concurrency control: ensuring the correct sequencing of the interactions or communications between different computational executions, and coordinating access to resources that are shared among executions. Potential problems include race conditions, deadlocks, and resource starvation. For example, consider the following algorithm to make withdrawals from a checking account represented by the shared resource balance:

<span id="mwdg"></span><span class="linenos" data-line="1" id="mwdw"></span><span class="kt" id="mweA">bool</span><span class="w" id="mweQ"> </span><span class="nf" id="mweg">withdraw</span><span class="p" id="mwew">(</span><span class="kt" id="mwfA">int</span><span class="w" id="mwfQ"> </span><span class="n" id="mwfg">withdrawal</span><span class="p" id="mwfw">)</span> <span class="linenos" data-line="2" id="mwgA"></span><span class="p" id="mwgQ">{</span> <span class="hll" id="mwgg"><span class="linenos" data-line="3" id="mwgw"></span><span class="w" id="mwhA"> </span><span class="k" id="mwhQ">if</span><span class="w" id="mwhg"> </span><span class="p" id="mwhw">(</span><span class="n" id="mwiA">balance</span><span class="w" id="mwiQ"> </span><span class="o" id="mwig">>=</span><span class="w" id="mwiw"> </span><span class="n" id="mwjA">withdrawal</span><span class="p" id="mwjQ">)</span> </span><span class="linenos" data-line="4" id="mwjg"></span><span class="w" id="mwjw"> </span><span class="p" id="mwkA">{</span> <span class="hll" id="mwkQ"><span class="linenos" data-line="5" id="mwkg"></span><span class="w" id="mwkw"> </span><span class="n" id="mwlA">balance</span><span class="w" id="mwlQ"> </span><span class="o" id="mwlg">-=</span><span class="w" id="mwlw"> </span><span class="n" id="mwmA">withdrawal</span><span class="p" id="mwmQ">;</span> </span><span class="linenos" data-line="6" id="mwmg"></span><span class="w" id="mwmw"> </span><span class="k" id="mwnA">return</span><span class="w" id="mwnQ"> </span><span class="nb" id="mwng">true</span><span class="p" id="mwnw">;</span> <span class="linenos" data-line="7" id="mwoA"></span><span class="w" id="mwoQ"> </span><span class="p" id="mwog">}</span><span class="w" id="mwow"> </span> <span class="linenos" data-line="8" id="mwpA"></span><span class="w" id="mwpQ"> </span><span class="k" id="mwpg">return</span><span class="w" id="mwpw"> </span><span class="nb" id="mwqA">false</span><span class="p" id="mwqQ">;</span> <span class="linenos" data-line="9" id="mwqg"></span><span class="p" id="mwqw">}</span>

Suppose balance = 500, and two concurrent threads make the calls withdraw(300) and withdraw(350). If line 3 in both operations executes before line 5 both operations will find that balance >= withdrawal evaluates to true, and execution will proceed to subtracting the withdrawal amount. However, since both processes perform their withdrawals, the total amount withdrawn will end up being more than the original balance. These sorts of problems with shared resources benefit from the use of concurrency control, or non-blocking algorithms.

Advantages

There are advantages of concurrent computing:

  • Increased program throughput—parallel execution of a concurrent algorithm allows the number of tasks completed in a given time to increase proportionally to the number of processors according to Gustafson's law.
  • High responsiveness for input/output—input/output-intensive programs mostly wait for input or output operations to complete. Concurrent programming allows the time that would be spent waiting to be used for another task.
  • More appropriate program structure—some problems and problem domains are well-suited to representation as concurrent tasks or processes. For example MVCC.

Sign in to keep reading

5 more chapters are free with a Lably account.

More in Computing and communication