core.async

Race condition when closing mults

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
  • Approval:
    Triaged

Description

When a mult is tapped at around the same time as the source channel is closed, the tapped channel may not be closed.

(require '[clojure.core.async :refer (chan mult tap close!)])
(let [s (chan)
      m (mult s)
      c (chan)]
  (tap m c)
  (close! s)
  (impl/closed? c))

The above code will sometimes return true, and sometimes return false.

Cause: This is caused by the following code in the mult function:

(if (nil? val)
  (doseq [[c close?] @cs]
    (when close? (close! c)))

Any channels tapped after cs is dereferenced will not be closed.

Approach: A possible solution to this could be to always close channels tapped to a closed source. i.e.

(let [s (chan)
      m (mult s)
      c (chan)]
  (close! s)
  (tap m c))  ;; will always close c

This could be achieved by adding a flag to the cs atom to denote whether the mult is open or closed. If it's closed, any tapped channel is closed automatically.

Activity

Rich Hickey made changes -
Field Original Value New Value
Assignee Rich Hickey [ richhickey ]
Alex Miller made changes -
Approval Triaged [ 10120 ]
Description When a mult is tapped at around the same time as the source channel is closed, the tapped channel may not be closed.

(let [s (chan)
      m (mult s)
      c (chan)]
  (tap m c)
  (close! s)
  (impl/closed? c))

The above code will sometimes return true, and sometimes return false. This is caused by the following code in the mult function:

(if (nil? val)
  (doseq [[c close?] @cs]
    (when close? (close! c)))

Any channels tapped after cs is dereferenced will not be closed.

A possible solution to this could be to always close channels tapped to a closed source. i.e.

(let [s (chan)
      m (mult s)
      c (chan)]
  (close! s)
  (tap m c)) ;; will always close c

This could be achieved by adding a flag to the cs atom to denote whether the mult is open or closed. If it's closed, any tapped channel is closed automatically.
When a mult is tapped at around the same time as the source channel is closed, the tapped channel may not be closed.

{code}
(require '[clojure.core.async :refer (chan mult tap close!)])
(let [s (chan)
      m (mult s)
      c (chan)]
  (tap m c)
  (close! s)
  (impl/closed? c))
{code}

The above code will sometimes return true, and sometimes return false.

*Cause:* This is caused by the following code in the {{mult}} function:

{code}
(if (nil? val)
  (doseq [[c close?] @cs]
    (when close? (close! c)))
{code}

Any channels tapped after cs is dereferenced will not be closed.

*Approach:* A possible solution to this could be to always close channels tapped to a closed source. i.e.

{code}
(let [s (chan)
      m (mult s)
      c (chan)]
  (close! s)
  (tap m c)) ;; will always close c
{code}

This could be achieved by adding a flag to the cs atom to denote whether the mult is open or closed. If it's closed, any tapped channel is closed automatically.
Labels mult

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated: