- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/colby_parsons_MMAth/text/channels.tex
raae9c17 r9509d67a 20 20 Neither Go nor \CFA channels have the restrictions of the early channel-based concurrent systems. 21 21 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}.22 Other 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}. 23 23 Boost channels only support asynchronous (non-blocking) operations, and Rust channels are limited to only having one consumer per channel. 24 24 Haskell channels are unbounded in size, and OCaml channels are zero-size. 25 25 These 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. 26 26 These 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. 27 Kotlin 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. 27 28 28 29 \section{Producer-Consumer Problem} … … 31 32 In 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. 32 33 In 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).34 As 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. 34 35 35 36 \section{Channel Size}\label{s:ChannelSize} … … 41 42 Fixed 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. 42 43 \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. 44 Infinite sized (unbounded) implies the communication is asymmetrically asynchronous, \ie the producer never waits but the consumer waits when the buffer is empty. 46 45 \end{enumerate} 47 46 … … 50 49 However, like MX, a buffer should ensure every value is eventually removed after some reasonable bounded time (no long-term starvation). 51 50 The simplest way to prevent starvation is to implement the buffer as a queue, either with a cyclic array or linked nodes. 51 While \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. 52 52 53 53 \section{First-Come First-Served} 54 As pointed out, a bounded buffer requires MX among multiple producers or consumers.54 As pointed out, a bounded buffer implementation often provides MX among multiple producers or consumers. 55 55 This MX should be fair among threads, independent of the \gls{fifo} buffer being fair among values. 56 56 Fairness among threads is called \gls{fcfs} and was defined by Lamport~\cite[p.~454]{Lamport74}. … … 66 66 67 67 \section{Channel Implementation}\label{s:chan_impl} 68 Currently, only the Go and Erlang programming languagesprovide user-level threading where the primary communication mechanism is channels.69 Both Go and Erlanghave user-level threading and preemptive scheduling, and both use channels for communication.70 Go providesmultiple homogeneous channels; each have a single associated type.68 The programming languages Go, Kotlin, and Erlang provide user-level threading where the primary communication mechanism is channels. 69 These languages have user-level threading and preemptive scheduling, and both use channels for communication. 70 Go and Kotlin provide multiple homogeneous channels; each have a single associated type. 71 71 Erlang, which is closely related to actor systems, provides one heterogeneous channel per thread (mailbox) with a typed receive pattern. 72 Go encouragesusers to communicate via channels, but provides them as an optional language feature.72 Go and Kotlin encourage users to communicate via channels, but provides them as an optional language feature. 73 73 On 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.74 Similar to Go and Kotlin, \CFA's channels are offered as an optional language feature. 75 75 76 76 While iterating on channel implementation, experiments were conducted that varied the producer-consumer algorithm and lock type used inside the channel. … … 83 83 The Go channel implementation utilizes cooperation among threads to achieve good performance~\cite{go:chan}. 84 84 This cooperation only occurs when producers or consumers need to block due to the buffer being full or empty. 85 After a producer blocks it must wait for a consumer to signal it and vice versa. 86 The consumer or producer that signals a blocked thread is called the signalling thread. 85 87 In 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; 86 88 \ie the blocking thread has no work to perform after it unblocks because the signalling threads has done this work. … … 88 90 First, each thread interacting with the channel only acquires and releases the internal channel lock once. 89 91 As 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 waitingfor signalled threads to run.92 The other advantage of Go's wait-morphing approach is that it eliminates the need to wait for signalled threads to run. 91 93 Note that the property of acquiring/releasing the lock only once can also be achieved with a different form of cooperation, called \Newterm{baton passing}. 92 94 Baton 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. … … 94 96 the 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. 95 97 While 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;98 In 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; 97 99 in 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. 98 100 … … 154 156 Thus, improperly handled \gls{toctou} issues with channels often result in deadlocks as threads performing the termination may end up unexpectedly blocking in their attempt to help other threads exit the system. 155 157 158 \subsubsection{Go Channel Close} 156 159 Go channels provide a set of tools to help with concurrent shutdown~\cite{go:chan} using a @close@ operation in conjunction with the \Go{select} statement. 157 160 The \Go{select} statement is discussed in \ref{s:waituntil}, where \CFA's @waituntil@ statement is compared with the Go \Go{select} statement. … … 175 178 Hence, due to Go's asymmetric approach to channel shutdown, separate synchronization between producers and consumers of a channel has to occur during shutdown. 176 179 177 \paragraph{\CFA channels} have access to an extensive exception handling mechanism~\cite{Beach21}. 180 \subsubsection{\CFA Channel Close} 181 \CFA channels have access to an extensive exception handling mechanism~\cite{Beach21}. 178 182 As such \CFA uses an exception-based approach to channel shutdown that is symmetric for both producers and consumers, and supports graceful shutdown. 179 183
Note: See TracChangeset
for help on using the changeset viewer.