Clarify thread-safety expectations of GRXWriters

pull/2861/head
Jorge Canizales 9 years ago
parent c678c30cf1
commit 67ce098ccf
  1. 9
      src/objective-c/RxLibrary/GRXBufferedPipe.h
  2. 10
      src/objective-c/RxLibrary/GRXForwardingWriter.h
  3. 13
      src/objective-c/RxLibrary/GRXImmediateWriter.h
  4. 39
      src/objective-c/RxLibrary/GRXWriter.h

@ -36,13 +36,11 @@
#import "GRXWriteable.h" #import "GRXWriteable.h"
#import "GRXWriter.h" #import "GRXWriter.h"
// A buffered pipe is a Writeable that also acts as a Writer (to whichever other writeable is passed // A buffered pipe is a Writer that also acts as a Writeable.
// to -startWithWriteable:).
// Once it is started, whatever values are written into it (via -writeValue:) will be propagated // Once it is started, whatever values are written into it (via -writeValue:) will be propagated
// immediately, unless flow control prevents it. // immediately, unless flow control prevents it.
// If it is throttled and keeps receiving values, as well as if it receives values before being // If it is throttled and keeps receiving values, as well as if it receives values before being
// started, it will buffer them and propagate them in order as soon as its state becomes // started, it will buffer them and propagate them in order as soon as its state becomes Started.
// GRXWriterStateStarted.
// If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and // If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and
// propagate the error immediately. // propagate the error immediately.
// //
@ -51,6 +49,9 @@
// pipe will keep buffering all data written to it, your application could run out of memory and // pipe will keep buffering all data written to it, your application could run out of memory and
// crash. If you want to react to flow control signals to prevent that, instead of using this class // crash. If you want to react to flow control signals to prevent that, instead of using this class
// you can implement an object that conforms to GRXWriter. // you can implement an object that conforms to GRXWriter.
//
// Thread-safety:
// The methods of an object of this class should not be called concurrently from different threads.
@interface GRXBufferedPipe : GRXWriter<GRXWriteable> @interface GRXBufferedPipe : GRXWriter<GRXWriteable>
// Convenience constructor. // Convenience constructor.

@ -33,11 +33,17 @@
#import "GRXWriter.h" #import "GRXWriter.h"
// A "proxy" class that simply forwards values, completion, and errors from its // A "proxy" class that simply forwards values, completion, and errors from its input writer to its
// input writer to its writeable. // writeable.
// It is useful as a superclass for pipes that act as a transformation of their // It is useful as a superclass for pipes that act as a transformation of their
// input writer, and for classes that represent objects with input and // input writer, and for classes that represent objects with input and
// output sequences of values, like an RPC. // output sequences of values, like an RPC.
//
// Thread-safety:
// All messages sent to this object need to be serialized. When it is started, the writer it wraps
// is started in the same thread. Manual state changes are propagated to the wrapped writer in the
// same thread too. Importantly, all messages the wrapped writer sends to its writeable need to be
// serialized with any message sent to this object.
@interface GRXForwardingWriter : GRXWriter @interface GRXForwardingWriter : GRXWriter
- (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER; - (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER;
@end @end

@ -36,10 +36,17 @@
#import "GRXWriter.h" #import "GRXWriter.h"
// Utility to construct GRXWriter instances from values that are immediately available when // Utility to construct GRXWriter instances from values that are immediately available when
// required. The returned writers all support pausing and early termination. // required.
// //
// Unless the writeable callback pauses them or stops them early, these writers will do all their // Thread-safety:
// interactions with the writeable before the start method returns. //
// An object of this class shouldn't be messaged concurrently by more than one thread. It will start
// messaging the writeable before |startWithWriteable:| returns, in the same thread. That is the
// only place where the writer can be paused or stopped prematurely.
//
// If a paused writer of this class is resumed, it will start messaging the writeable, in the same
// thread, before |setState:| returns. Because the object can't be legally accessed concurrently,
// that's the only place where it can be paused again (or stopped).
@interface GRXImmediateWriter : GRXWriter @interface GRXImmediateWriter : GRXWriter
// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to // Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to

@ -65,26 +65,27 @@ typedef NS_ENUM(NSInteger, GRXWriterState) {
GRXWriterStateFinished GRXWriterStateFinished
}; };
// An object that conforms to this protocol can produce, on demand, a sequence // An GRXWriter object can produce, on demand, a sequence of values. The sequence may be produced
// of values. The sequence may be produced asynchronously, and it may consist of // asynchronously, and it may consist of any number of elements, including none or an infinite
// any number of elements, including none or an infinite number. // number.
// //
// GRXWriter is the active dual of NSEnumerator. The difference between them // GRXWriter is the active dual of NSEnumerator. The difference between them is thus whether the
// is thus whether the object plays an active or passive role during usage: A // object plays an active or passive role during usage: A user of NSEnumerator pulls values off it,
// user of NSEnumerator pulls values off it, and passes the values to a writeable. // and passes the values to a writeable. A user of GRXWriter, though, just gives it a writeable, and
// A user of GRXWriter, though, just gives it a writeable, and the // the GRXWriter instance pushes values to the writeable. This makes this protocol suitable to
// GRXWriter instance pushes values to the writeable. This makes this protocol // represent a sequence of future values, as well as collections with internal iteration.
// suitable to represent a sequence of future values, as well as collections
// with internal iteration.
// //
// An instance of GRXWriter can start producing values after a writeable is // An instance of GRXWriter can start producing values after a writeable is passed to it. It can
// passed to it. It can also be commanded to finish the sequence immediately // also be commanded to finish the sequence immediately (with an optional error). Finally, it can be
// (with an optional error). Finally, it can be asked to pause, but the // asked to pause, and resumed later. All GRXWriter objects support pausing and early termination.
// conforming instance is not required to oblige.
// //
// Unless otherwise indicated by a conforming class, no messages should be sent // Thread-safety:
// concurrently to a GRXWriter. I.e., conforming classes aren't required to //
// be thread-safe. // State transitions take immediate effect if the object is used from a single thread. Subclasses
// might offer stronger guarantees.
//
// Unless otherwise indicated by a conforming subclass, no messages should be sent concurrently to a
// GRXWriter. I.e., conforming classes aren't required to be thread-safe.
@interface GRXWriter : NSObject @interface GRXWriter : NSObject
// This property can be used to query the current state of the writer, which // This property can be used to query the current state of the writer, which
@ -110,9 +111,5 @@ typedef NS_ENUM(NSInteger, GRXWriterState) {
// //
// This method might only be called on writers in the Started or Paused // This method might only be called on writers in the Started or Paused
// state. // state.
//
// TODO(jcanizales): Consider adding some guarantee about the immediacy of that
// stopping. I know I've relied on it in part of the code that uses this, but
// can't remember the details in the presence of concurrency.
- (void)finishWithError:(NSError *)errorOrNil; - (void)finishWithError:(NSError *)errorOrNil;
@end @end

Loading…
Cancel
Save