Skip to content

Commit

Permalink
upgrade threads from experimental to stable-with-caveats
Browse files Browse the repository at this point in the history
more threading doc edits
  • Loading branch information
JeffBezanson committed May 1, 2020
1 parent e3f91bd commit a8b5126
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 23 deletions.
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ Command-line option changes

Multi-threading changes
-----------------------

* Parts of the multi-threading API are now considered stable, with caveats.
This includes all identifiers exported from `Base.Threads`, plus
`Threads.@spawn` and `Threads.Condition`.

Build system changes
--------------------
Expand Down
2 changes: 1 addition & 1 deletion base/threadingconstructs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ constructed underlying closure. This allows you to insert the _value_ of a varia
isolating the aysnchronous code from changes to the variable's value in the current task.
!!! note
This feature is currently considered experimental.
See the manual chapter on threading for important caveats.
!!! compat "Julia 1.3"
This macro is available as of Julia 1.3.
Expand Down
2 changes: 1 addition & 1 deletion base/threads.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

"""
Experimental multithreading support.
Multithreading support.
"""
module Threads

Expand Down
20 changes: 14 additions & 6 deletions doc/src/base/multi-threading.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
# [Multi-Threading](@id lib-multithreading)

This experimental interface supports Julia's multi-threading capabilities. Types and functions
described here might (and likely will) change in the future.

```@docs
Base.Threads.threadid
Base.Threads.nthreads
Base.Threads.@threads
Base.Threads.@spawn
Base.Threads.threadid
Base.Threads.nthreads
```

## Synchronization

```@docs
Base.Threads.Condition
Base.Threads.Event
```

See also [Synchronization](@ref lib-task-sync).

## Atomic operations

```@docs
Base.Threads.Atomic
Base.Threads.atomic_cas!
Expand All @@ -31,7 +39,7 @@ Base.Threads.atomic_fence
Base.@threadcall
```

# Low-level synchronization primitives
## Low-level synchronization primitives

These building blocks are used to create the regular synchronization objects.

Expand Down
20 changes: 13 additions & 7 deletions doc/src/base/parallel.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
Core.Task
Base.@task
Base.@async
Base.@sync
Base.asyncmap
Base.asyncmap!
Base.fetch(t::Task)
Base.current_task
Base.istaskdone
Base.istaskstarted
Expand All @@ -17,21 +15,25 @@ Base.task_local_storage(::Any, ::Any)
Base.task_local_storage(::Function, ::Any, ::Any)
```

# Scheduling
## Scheduling

```@docs
Base.yield
Base.yieldto
Base.sleep
Base.schedule
```

## [Synchronization](@id lib-task-sync)

```@docs
Base.@sync
Base.wait
Base.fetch(t::Task)
Base.timedwait
Base.Condition
Base.Threads.Condition
Base.notify
Base.schedule
Base.Threads.Event
Base.Semaphore
Base.acquire
Expand All @@ -43,7 +45,11 @@ Base.unlock
Base.trylock
Base.islocked
Base.ReentrantLock
```

## Channels

```@docs
Base.Channel
Base.Channel(::Function)
Base.put!(::Channel, ::Any)
Expand Down
14 changes: 7 additions & 7 deletions doc/src/manual/asynchronous-programming.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This sort of scenario falls in the domain of asynchronous programming, sometimes
also referred to as concurrent programming (since, conceptually, multiple things
are happening at once).

To address these scenarios, Julia provides `Task`s (also known by several other
To address these scenarios, Julia provides [`Task`](@ref)s (also known by several other
names, such as symmetric coroutines, lightweight threads, cooperative multitasking,
or one-shot continuations).
When a piece of computing work (in practice, executing a particular function) is designated as
Expand All @@ -26,7 +26,7 @@ calls, where the called function must finish executing before control returns to
You can think of a `Task` as a handle to a unit of computational work to be performed.
It has a create-start-run-finish lifecycle.
Tasks are created by calling the `Task` constructor on a 0-argument function to run,
or using the `@task` macro:
or using the [`@task`](@ref) macro:

```
julia> t = @task begin; sleep(5); println("done"); end
Expand All @@ -36,7 +36,7 @@ Task (runnable) @0x00007f13a40c0eb0
`@task x` is equivalent to `Task(()->x)`.

This task will wait for five seconds, and then print `done`. However, it has not
started running yet. We can run it whenever we're ready by calling `schedule`:
started running yet. We can run it whenever we're ready by calling [`schedule`](@ref):

```
julia> schedule(t);
Expand All @@ -47,12 +47,12 @@ That is because it simply adds `t` to an internal queue of tasks to run.
Then, the REPL will print the next prompt and wait for more input.
Waiting for keyboard input provides an opportunity for other tasks to run,
so at that point `t` will start.
`t` calls `sleep`, which sets a timer and stops execution.
`t` calls [`sleep`](@ref), which sets a timer and stops execution.
If other tasks have been scheduled, they could run then.
After five seconds, the timer fires and restarts `t`, and you will see `done`
printed. `t` is then finished.

The `wait` function blocks the calling task until some other task finishes.
The [`wait`](@ref) function blocks the calling task until some other task finishes.
So for example if you type

```
Expand All @@ -63,8 +63,8 @@ instead of only calling `schedule`, you will see a five second pause before
the next input prompt appears. That is because the REPL is waiting for `t`
to finish before proceeding.

It is common to want to create a task and schedule it right away, so a
macro called `@async` is provided for that purpose --- `@async x` is
It is common to want to create a task and schedule it right away, so the
macro [`@async`](@ref) is provided for that purpose --- `@async x` is
equivalent to `schedule(@task x)`.

## Communicating with Channels
Expand Down
30 changes: 30 additions & 0 deletions doc/src/manual/multi-threading.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,33 @@ therefore a blocking call like other Julia APIs.
It is very important that the called function does not call back into Julia, as it will segfault.

`@threadcall` may be removed/changed in future versions of Julia.

## Caveats

At this time, most operations in the Julia runtime and standard libraries
are thread safe.
However, in some areas work on stabilizing thread support is ongoing.
Multi-threaded programming has many inherent difficulties, and if a program
using threads exhibits unusual or undesirable behavior (e.g. crashes or
mysterious results), thread interactions should typically be suspected first.

There are a few specific limitations and warnings to be aware of when using
threads in Julia:

* Base collection types require manual locking if used simultaneously by
multiple threads (common examples include `push!` on arrays, or inserting
items into a `Dict`).
* After a task starts running on a certain thread (e.g. via `@spawn`), it
will always be restarted on the same thread after blocking. In the future
this limitation will be removed, and tasks will migrate between threads.
* `@threads` currently uses a static schedule, using all threads and assigning
equal iteration counts to each. In the future the default schedule is likely
to change to be dynamic.
* The schedule used by `@spawn` is nondeterministic and should not be relied on.
* Compute-bound, non-memory-allocating tasks can prevent garbage collection from
running in other threads that are allocating memory. In these cases it may
be necessary to insert a manual call to `GC.safepoint()` to allow GC to run.
This limitation will be removed in the future.
* Avoid using finalizers in conjunction with threads, particularly if they
operate on objects shared by multiple threads.
* Avoid running top-level operations, e.g. `include`, in parallel.

0 comments on commit a8b5126

Please sign in to comment.