Changeset 47b7142


Ignore:
Timestamp:
Jul 20, 2023, 4:47:06 PM (16 months ago)
Author:
caparsons <caparson@…>
Branches:
master
Children:
d4c1d1f
Parents:
c03c1ac
Message:

reworked 7.5.3 of thesis

File:
1 edited

Legend:

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

    rc03c1ac r47b7142  
    477477\end{tabular}
    478478\end{cquote}
    479 These examples are basically equivalence.
     479These examples are basically equivalent.
    480480Here, the multiple timeouts are useful because the durations can change during execution and the separate clauses provide different code blocks if a timeout triggers.
    481481Multiple timeouts can also be used with @and@ to provide a minimal delay before proceeding.
     
    499499In either case, after the WUT unblocks it is safe to execute its the corresponding code block knowing access to the resource is protected by the lock or the read-only state of the future.
    500500Similarly, for channels, when an outside thread inserts a value into a channel, it must unblock the WUT.
    501 However, for channels, there is a race issue.
    502 If the outside thread inserts into the channel and unblocks the WUT, there is a race such that, another thread can remove the channel data, so after the WUT unblocks and attempts to remove from the buffer, it fails, and the WUT must reblock (busy waiting).
     501However, for channels, there is a race condition that poses an issue.
     502If the outside thread inserts into the channel and unblocks the WUT, there is a race where another thread can remove the channel data, so after the WUT unblocks and attempts to remove from the buffer, it fails, and the WUT must reblock (busy waiting).
    503503This scenario is a \gls{toctou} race that needs to be consolidated.
    504504To close the race, the outside thread must detect this case and insert directly into the left-hand side of the channel expression (@i << chan@) rather than into the channel, and then unblock the WUT.
     
    522522
    523523It was deemed important that exclusive-or semantics are maintained when only @or@ operators are used, so this situation has been special-cased, and is handled by having all clauses race to set a value \emph{before} operating on the channel.
    524 \PAB{explain how this is handled.}
    525 
    526 \PAB{I'm lost here to the end of the section. You have no example of the case you want to discuss so a made something up.}
     524Consider the following example with three threads running concurrently.
     525\begin{cfa}
     526channel A, B; // zero size channels
     527
     528// Thread 1:
     529waituntil( i << A ) {}
     530or waituntil( i << B ) {}
     531
     532// Thread 2:
     533waituntil( A << 1 ) {}
     534
     535// Thread 3:
     536waituntil( B << 2 ) {}
     537\end{cfa}
     538
     539For Thread 1 to have exclusive-or semantics, it must only consume from exactly one of @A@ or @B@.
     540As such, Thread 2 and 3 must race to establish the winning clause of the @waituntil@ in Thread 1.
     541This race is consolidated by Thread 2 and 3 each attempting to set a pointer to the winning clause's @select_node@ address using \gls{cas}.
     542The winner will successfully \gls{cas} the address, insert the value and then signal Thread 1, whereas the loser will fail their \gls{cas}.
     543If there is space in the channel, the losing thread may proceed with their channel operation and not signal, otherwise if there is no space they block as they would in a standard channel insert operation.
     544It is important that threads race \emph{before} operating on the channel, since if they lose the race they may need to take a different action with respect to their channel operation.
     545In the example case, the winner will handoff their value to Thread 1 and the loser will block.
     546If the race was consolidated after the operation, both Thread 2 and 3 could potentially write into @i@ concurrently, which would be erroneous behaviour.
    527547
    528548Channels introduce another interesting consideration in their implementation.
    529 Supporting both reading and writing to a channel in a @waituntil@ means that one @waituntil@ clause may be the notifier by another @waituntil@ clause.
    530 \begin{cfa}
    531 waituntil( i << A ) { @B << i;@ }
    532 or waituntil( i << B ) { @A << i;@ }
    533 \end{cfa}
     549Supporting both reading and writing to a channel in a @waituntil@ means that one @waituntil@ clause may be the notifier of another @waituntil@ clause.
    534550This poses a problem when dealing with the special-cased @or@ where the clauses need to win a race to operate on a channel.
    535 When both a special-case @or@ is inserting to a channel on one thread and another thread is blocked in a special-case @or@ consuming from the same channel there is not one but two races that need to be consolidated by the inserting thread.
    536 (This race can also occur in the mirrored case with a blocked producer and signalling consumer.)
    537 For the producing thread to know that the insert succeeded, they need to win the race for their own @waituntil@ and win the race for the other @waituntil@.
     551
     552Consider the following example, alongside a described ordering of events to highlight the race.
     553Assume Thread 1 executes first, registers with channel @A@ and proceeds since it is empty and then is interrupted before registering with @B@.
     554Thread 2 similarly registers with channel @B@, and proceeds since it doesn't have space to insert and then is interrupted before registering with @A@.
     555At this point Thread 1 and 2 resume execution.
     556There is now a race that must be dealt with on two fronts.
     557If Thread 1 and 2 only race to \gls{cas} a winning clause for their own @waituntil@, Thread 1 may think that it successfully removed from @B@ and Thread 2 may think it successfully inserted into @A@, when only one of these operations can occur.
     558\begin{cfa}
     559channel A, B; // zero size channels
     560
     561// Thread 1:
     562waituntil( i << A ) {}
     563or waituntil( i << B ) {}
     564
     565// Thread 2:
     566waituntil( B << 2 ) {}
     567or waituntil( A << 1 ) {}
     568\end{cfa}
    538569
    539570Go solves this problem in their select statement by acquiring the internal locks of all channels before registering the select on the channels.
    540 This eliminates the race since no other threads can operate on the blocked channel since its lock is held.
     571This eliminates the race shown above since both Thread 1 and 2 cannot both be registering at the same time.
    541572This approach is not used in \CFA since the @waituntil@ is polymorphic.
    542573Not all types in a @waituntil@ have an internal lock, and when using non-channel types acquiring all the locks incurs extra unneeded overhead.
    543574Instead, this race is consolidated in \CFA in two phases by having an intermediate pending status value for the race.
    544 This race case is detectable, and if detected, the outside thread first races to set its own race flag to be pending.
    545 If it succeeds, it then attempts to set the WUT's race flag to its success value.
    546 If the outside thread successfully sets the WUT's race flag, then the operation can proceed, if not the signalling threads set its own race flag back to the initial value.
    547 If any other threads attempt to set the producer's flag and see a pending value, they will wait until the value changes before proceeding to ensure that in the case that the producer fails, the signal will not be lost.
     575This race case is detectable, and if detected, each thread first races to set its own @waituntil@ race pointer to be pending.
     576If it succeeds, it then attempts to set the other thread's @waituntil@ race pointer to its success value.
     577If either thread successfully sets the the other thread's @waituntil@ race pointer, then the operation can proceed, if not the signalling threads set its own race pointer back to the initial value and repeats.
     578This retry mechanism can potentially introduce a livelock, but in practice a livelock here is highly unlikely.
     579Furthermore, the likelihood of a livelock here is zero unless the program is in the niche case of having two or more exclusive-or waituntils with 2 or more clauses in reverse order of priority.
     580This livelock case could be fully eliminated using locks like Go, or if a \gls{dcas} instruction is available.
     581If any other threads attempt to set a WUT's race pointer and see a pending value, they will wait until the value changes before proceeding to ensure that in the case that the WUT fails, the signal will not be lost.
    548582This protocol ensures that signals will not be lost and that the two races can be resolved in a safe manner.
    549583
    550584Channels in \CFA have exception based shutdown mechanisms that the @waituntil@ statement needs to support.
    551 These exception mechanisms were what brought in the @on_selected@ routine.
     585These exception mechanisms are supported through the @on_selected@ routine.
    552586This routine is needed by channels to detect if they are closed upon waking from a @waituntil@ statement, to ensure that the appropriate behaviour is taken and an exception is thrown.
    553587
Note: See TracChangeset for help on using the changeset viewer.