Created
July 22, 2019 07:07
-
-
Save ubershmekel/fc88307f827b3f0384c64117001c947b to your computer and use it in GitHub Desktop.
An example race condition in JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An example race condition in JavaScript | |
// When you run this script using Node or in a browser, you'll find it | |
// does not print "Ended with 0", but a random number. Even though the functions running | |
// simply loop 100 iterations of adding and subtracting. The reason the end result is random | |
// is because the sleeps are of random duration and the time between the read of the variable | |
// causes the eventual write to be incorrect when `adder` and `subber` interleave. | |
// This problem is similar to https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use | |
let number = 0; | |
const times = 100; | |
function sleep() { | |
return new Promise((resolve) => setTimeout(resolve, Math.random() * 5)); | |
} | |
async function adder() { | |
for (let i = 0; i < times; i++) { | |
await sleep(); | |
let read = number; | |
read = read + 1; | |
await sleep(); | |
number = read; | |
} | |
} | |
async function subber() { | |
for (let i = 0; i < times; i++) { | |
await sleep(); | |
let read = number; | |
read = read - 1; | |
await sleep(); | |
number = read; | |
} | |
} | |
async function main() { | |
console.log("Started with", number); | |
await Promise.all([ | |
adder(), | |
subber(), | |
]); | |
console.log("Ended with", number); | |
} | |
main() | |
.then(() => console.log("All done")) | |
.catch((err) => console.error(err)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment