Ignore:
Timestamp:
Sep 11, 2023, 12:55:43 PM (9 months ago)
Author:
caparsons <caparson@…>
Branches:
master
Children:
c8ec58e
Parents:
3ee8853
Message:

Incorporated changes in response to Trevor's comments.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/colby_parsons_MMAth/text/channels.tex

    r3ee8853 r9509d67a  
    2020Neither Go nor \CFA channels have the restrictions of the early channel-based concurrent systems.
    2121
    22 Other popular languages and libraries that provide channels include C++ Boost~\cite{boost:channel}, Rust~\cite{rust:channel}, Haskell~\cite{haskell:channel}, and OCaml~\cite{ocaml:channel}.
     22Other popular languages and libraries that provide channels include C++ Boost~\cite{boost:channel}, Rust~\cite{rust:channel}, Haskell~\cite{haskell:channel}, OCaml~\cite{ocaml:channel}, and Kotlin~\cite{kotlin:channel}.
    2323Boost channels only support asynchronous (non-blocking) operations, and Rust channels are limited to only having one consumer per channel.
    2424Haskell channels are unbounded in size, and OCaml channels are zero-size.
    2525These restrictions in Haskell and OCaml are likely due to their functional approach, which results in them both using a list as the underlying data structure for their channel.
    2626These languages and libraries are not discussed further, as their channel implementation is not comparable to the bounded-buffer style channels present in Go and \CFA.
     27Kotlin channels are comparable to Go and \CFA, but unfortunately they were not identified as a comparator until after presentation of this thesis and are omitted due to time constraints.
    2728
    2829\section{Producer-Consumer Problem}
     
    3132In the problem, threads interact with a buffer in two ways: producing threads insert values into the buffer and consuming threads remove values from the buffer.
    3233In general, a buffer needs protection to ensure a producer only inserts into a non-full buffer and a consumer only removes from a non-empty buffer (synchronization).
    33 As well, a buffer needs protection from concurrent access by multiple producers or consumers attempting to insert or remove simultaneously (MX).
     34As well, a buffer needs protection from concurrent access by multiple producers or consumers attempting to insert or remove simultaneously, which is often provided by MX.
    3435
    3536\section{Channel Size}\label{s:ChannelSize}
     
    4142Fixed sized (bounded) implies the communication is mostly asynchronous, \ie the producer can proceed up to the buffer size and vice versa for the consumer with respect to removal, at which point the producer/consumer would wait.
    4243\item
    43 Infinite sized (unbounded) implies the communication is asynchronous, \ie the producer never waits but the consumer waits when the buffer is empty.
    44 Since memory is finite, all unbounded buffers are ultimately bounded;
    45 this restriction must be part of its implementation.
     44Infinite sized (unbounded) implies the communication is asymmetrically asynchronous, \ie the producer never waits but the consumer waits when the buffer is empty.
    4645\end{enumerate}
    4746
     
    5049However, like MX, a buffer should ensure every value is eventually removed after some reasonable bounded time (no long-term starvation).
    5150The simplest way to prevent starvation is to implement the buffer as a queue, either with a cyclic array or linked nodes.
     51While \gls{fifo} is not required for producer-consumer problem correctness, it is a desired property in channels as it provides predictable and often relied upon channel ordering behaviour to users.
    5252
    5353\section{First-Come First-Served}
    54 As pointed out, a bounded buffer requires MX among multiple producers or consumers.
     54As pointed out, a bounded buffer implementation often provides MX among multiple producers or consumers.
    5555This MX should be fair among threads, independent of the \gls{fifo} buffer being fair among values.
    5656Fairness among threads is called \gls{fcfs} and was defined by Lamport~\cite[p.~454]{Lamport74}.
     
    6666
    6767\section{Channel Implementation}\label{s:chan_impl}
    68 Currently, only the Go and Erlang programming languages provide user-level threading where the primary communication mechanism is channels.
    69 Both Go and Erlang have user-level threading and preemptive scheduling, and both use channels for communication.
    70 Go provides multiple homogeneous channels; each have a single associated type.
     68The programming languages Go, Kotlin, and Erlang provide user-level threading where the primary communication mechanism is channels.
     69These languages have user-level threading and preemptive scheduling, and both use channels for communication.
     70Go and Kotlin provide multiple homogeneous channels; each have a single associated type.
    7171Erlang, which is closely related to actor systems, provides one heterogeneous channel per thread (mailbox) with a typed receive pattern.
    72 Go encourages users to communicate via channels, but provides them as an optional language feature.
     72Go and Kotlin encourage users to communicate via channels, but provides them as an optional language feature.
    7373On the other hand, Erlang's single heterogeneous channel is a fundamental part of the threading system design; using it is unavoidable.
    74 Similar to Go, \CFA's channels are offered as an optional language feature.
     74Similar to Go and Kotlin, \CFA's channels are offered as an optional language feature.
    7575
    7676While iterating on channel implementation, experiments were conducted that varied the producer-consumer algorithm and lock type used inside the channel.
     
    8383The Go channel implementation utilizes cooperation among threads to achieve good performance~\cite{go:chan}.
    8484This cooperation only occurs when producers or consumers need to block due to the buffer being full or empty.
     85After a producer blocks it must wait for a consumer to signal it and vice versa.
     86The consumer or producer that signals a blocked thread is called the signalling thread.
    8587In these cases, a blocking thread stores their relevant data in a shared location and the signalling thread completes the blocking thread's operation before waking them;
    8688\ie the blocking thread has no work to perform after it unblocks because the signalling threads has done this work.
     
    8890First, each thread interacting with the channel only acquires and releases the internal channel lock once.
    8991As a result, contention on the internal lock is decreased; only entering threads compete for the lock since unblocking threads do not reacquire the lock.
    90 The other advantage of Go's wait-morphing approach is that it eliminates the bottleneck of waiting for signalled threads to run.
     92The other advantage of Go's wait-morphing approach is that it eliminates the need to wait for signalled threads to run.
    9193Note that the property of acquiring/releasing the lock only once can also be achieved with a different form of cooperation, called \Newterm{baton passing}.
    9294Baton passing occurs when one thread acquires a lock but does not release it, and instead signals a thread inside the critical section, conceptually ``passing'' the mutual exclusion from the signalling thread to the signalled thread.
     
    9496the wait-morphing approach has threads cooperate by completing the signalled thread's operation, thus removing a signalled thread's need for mutual exclusion after unblocking.
    9597While baton passing is useful in some algorithms, it results in worse channel performance than the Go approach.
    96 In the baton-passing approach, all threads need to wait for the signalled thread to reach the front of the ready queue, context switch, and run before other operations on the channel can proceed, since the signalled thread holds mutual exclusion;
     98In the baton-passing approach, all threads need to wait for the signalled thread to unblock and run before other operations on the channel can proceed, since the signalled thread holds mutual exclusion;
    9799in the wait-morphing approach, since the operation is completed before the signal, other threads can continue to operate on the channel without waiting for the signalled thread to run.
    98100
Note: See TracChangeset for help on using the changeset viewer.