<INTERFACE> The <CD/SyncVar/ structure <SEEALSO> <STRREF TOPID/CML/ </SEEALSO> <PP> The <STRREF TOPID NOLINK/SyncVar/ structure provides <BF/Id/-style synchronous variables (or memory cells). These variables have two states: <IT/empty/ and <IT/full/. An attempt to read a value from an empty variable blocks the calling thread until there is a value available. An attempt to put a value into a variable that is full results in the <SPEC> <EXN>Put <COMMENT> <PP> This exception is raised when an attempt is made to put a value into a value that is already full (see <VALREF/iPut/ and <VALREF/mPut/). <SPEC> <TYPE><TYPARAM>'a<ID>ivar <COMMENT> <PP> This is the type constructor for I-structured variables. I-structured variables are write-once variables that provide synchronization on read operations. They are especially useful for one-shot communications, such as reply messages in client/server protocols, and can also be used to implement shared incremental data structures. <SPEC> <VAL>iVar<TY>unit -> 'a ivar <COMMENT> <PROTOTY> iVar () </PROTOTY> creates a new empty I-variable. <SPEC> <VAL>iPut<TY>('a ivar * 'a) -> unit <RAISES><EXNREF/Put/ <COMMENT> <PROTOTY> iPut (<ARG/iv/, <ARG/x/) </PROTOTY> fills the I-variable <ARG/iv/ with the value <ARG/x/. Any threads that are blocked on <ARG/iv/ will be resumed. If <ARG/iv/ already has a value in it, then the <EXNREF/Put/ exception is raised. <SPEC> <VAL>iGet<TY>'a ivar -> 'a <COMMENT> <PROTOTY> iGet <ARG/iv/ </PROTOTY> returns the contents of the I-variable <ARG/iv/. If the variable is empty, then the calling thread blocks until the variable becomes full. <SPEC> <VAL>iGetEvt<TY>'a ivar -> 'a event <COMMENT> <PROTOTY> iGetEvt <ARG/iv/ </PROTOTY> returns an event-value that represents the <VALREF/iGet/ operation on <ARG/iv/. <SPEC> <VAL>iGetPoll<TY>'a ivar -> 'a option <COMMENT> <PP> This is a non-blocking version of <VALREF/iGet/. If the corresponding blocking form would block, then it returns <VAL>sameIVar<TY>('a ivar * 'a ivar) -> bool <COMMENT> <PROTOTY> sameIVar (<ARG/iv1/, <ARG/iv2/) </PROTOTY> returns <CD/true/, if <ARG/iv1/ and <ARG/iv2/ are the same I-variable. <SPEC> <TYPE><TYPARAM>'a<ID>mvar <COMMENT> <PP> This is the type constructor for M-structured variables. Unlike <TYREF/ivar/ values, M-structured variables may be updated multiple times. Like I-variables, however, they may only be written if they are empty. <SPEC> <VAL>mVar<TY>unit -> 'a mvar <COMMENT> <PROTOTY> mVar () </PROTOTY> creates a new empty M-variable. <SPEC> <VAL>mVarInit<TY>'a -> 'a mvar <COMMENT> <PROTOTY> mVarInit <ARG/x/ </PROTOTY> creates a new M-variable initialized to <ARG/x/. <SPEC> <VAL>mPut<TY>('a mvar * 'a) -> unit <RAISES><EXNREF/Put/ <COMMENT> <PROTOTY> mPut (<ARG/mv/, <ARG/x/) </PROTOTY> fills the M-variable <ARG/mv/ with the value <ARG/x/. Any threads that are blocked on <ARG/mv/ will be resumed. If <ARG/mv/ already has a value in it, then the <EXNREF/Put/ exception is raised. <SPEC> <VAL>mTake<TY>'a mvar -> 'a <COMMENT> <PROTOTY> mTake <ARG/mv/ </PROTOTY> removes and returns the contents of the M-variable <ARG/mv/ making it empty. If the variable is already empty, then the calling thread is blocked until a value is available. <SPEC> <VAL>mTakeEvt<TY>'a mvar -> 'a event <COMMENT> <PROTOTY> mTakeEvt <ARG/mv/ </PROTOTY> returns an event-value that represents the <VALREF/mTake/ operation on <ARG/mv/. <SPEC> <VAL>mGet<TY>'a mvar -> 'a <COMMENT> <PROTOTY> mGet <ARG/mv/ </PROTOTY> returns the contents of the M-variable <ARG/mv/ without emptying the variable; if the variable is empty, then the thread blocks until a value is available. It is equivalent to the code: `let val x = <VALREF/mTake/ <ARG/mv/ in <VALREF/mPut/(<ARG/mv/, x); x end` <SPEC> <VAL>mGetEvt<TY>'a mvar -> 'a event <COMMENT> <PROTOTY> mGetEvt <ARG/mv/ </PROTOTY> returns an event-value that represents the <VALREF/mGet/ operation on <ARG/mv/. <SPEC> <VAL>mTakePoll<TY>'a mvar -> 'a option <VAL>mGetPoll<TY>'a mvar -> 'a option <COMMENT> <PP> These are non-blocking versions of <VALREF/mTake/ and <VALREF/mGet/ (respectively). If the corresponding blocking form would block, then they return <VAL>mSwap<TY>('a mvar * 'a) -> 'a <COMMENT> <PROTOTY> mSwap (<ARG/mv/, <ARG/newV/) </PROTOTY> puts the value <ARG/newV/ into the M-variable <ARG/mv/ and returns the previous contents. If the variable is empty, then the thread blocks until a value is available. It is equivalent to the code: `let val x = <VALREF/mTake/ <ARG/mv/ in <VALREF/mPut/(<ARG/mv/, <ARG/newV/); x end` except that <CD/mSwap/ is executed atomically. <SPEC> <VAL>mSwapEvt<TY>('a mvar * 'a) -> 'a event <COMMENT> <PROTOTY> mSwapEvt (<ARG/mv/, <ARG/newV/) </PROTOTY> returns an event-value that represents the <VALREF/mSwap/ operation on <ARG/mv/ and <ARG/newV/. <SPEC> <VAL>sameMVar<TY>('a mvar * 'a mvar) -> bool <COMMENT> <PROTOTY> sameMVar (<ARG/mv1/, <ARG/mv2/) </PROTOTY> returns <CD/true/, if <ARG/mv1/ and <ARG/mv2/ are the same M-variable. </STRUCTURE> <PP> I-variables provide a useful mechanism for implementing the reply communication in request/reply protocols (in cases where the server does not care if the reply is accepted). They may also be used to implement incremental data structures and streams; for example, the <STRREF>Multicast</STRREF> structure uses I-variables to implement its multicast channels. <PP> A disciplined use of M-variables can provide an atomic read-modify-write operation. </INTERFACE>