A simple javascript threading experiment with setTimeout

  • fennng 

I am going to add a global queue object to my nodejs express program, then this raises a concern of thread safety.

I am implementing a queue with only 10 elements, the older elements will be throw away. So I wrote the following code to test.

In the following code, the if (queue.length > 10) can cause problem. Because when both thread run into this block and both finish pushing the element, we will have 12 elements in the queue.

For example
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]

The new elements in this queue is 22, and 23.

Now thread 1 will do a slice and make the queue to be

[13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

At this point, because the queue length is 10, then the thread 2 will not do the slice. The pushed element 23 is gone.

If thread 2 read the queue length before thread 1 slice it. Then thread 2 will slice it again.

the array become

[14, 15, 16, 17, 18, 19, 20, 21, 22]

Only 9 element in the queue, 13 is gone.

let queue = [];
let threads = 100000;
for (let i = 0; i < threads; i++) {
    setTimeout(() => {
        queue.push(i);
        // This line can have a dirty read
        if (queue.length > 10) {
            queue = queue.slice (1, 11);
        }

        if (i >= threads - 10) {
            console.log(queue);
        }
    }, 1000);
}

But when I tested this in the browser. it never failed. It’s very interesting.

A small improvement is using a temp variable to hold the original queue outside the if block, then use the temp var in the if block. It will make sure only 1 element will be missing.

let queue = [];
let threads = 100000;
for (let i = 0; i < threads; i++) {
    setTimeout(() => {
        queue.push(i);
       let tempQueue = queue;
        // This line can have a dirty read
        if (queue.length > 10) {
            queue = tempQueue.slice (1, 11);
        }

        if (i >= threads - 10) {
            console.log(queue);
        }
    }, 1000);
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注