【正文】
單的優(yōu)勢,但我們指的讀者富爾等。類的組成控制一個復(fù)雜的的打字紀律,防止“消息不理解為“在運行時的錯誤。 public int g (int j ) { return j to f 。如果這只因為線程的身份可以得到平等檢查,這個問題將是相當學(xué)術(shù)。} } public int f (int i) { Thunk t = new Thunk()。 public int g (int j ) { t . reply( j )。從而 一個異步方法可以覆蓋一個 void 類型, 委托 void 類型,可以創(chuàng)建一個異步方法, 一個異步方法可以實現(xiàn)一個接口 void 方法 而不是相反。 一個簡單的細胞類 我們先從一個簡單的地方細胞類的實現(xiàn)。 } public void Put(object o) amp。 return o。 輸出和弦。 含蓄。 (相反可能有任意數(shù)量的客戶端線程阻塞與掛起的調(diào)用,把獲取,甚至同時運行的語句返回 0 到之前的變量 體。一個典型的解決這個問題,使用傳統(tǒng)的并發(fā)原語在 Modula3 給出由,比勒爾 [1989]。 async idle() {s(1)。 async s(int n) { if (n == 1) idle()。 } 每一個版本如下規(guī)定相應(yīng)的要求,不變是鎖狀態(tài)(沒有消息,一條消息空閑(),或單線程的種類和數(shù)量相匹配,目前消息小號 N 0( N))持有該鎖(獨家線程,沒有線程,或 n 共享的線程)。 } private int n = 0。 } public void Shared() amp。 async s() { if (??n == 0) idle()。 } 僅我們的執(zhí)行和底層操作系統(tǒng)調(diào)度提供基本的公平屬性例如:如果有足夠的等候和弦對象的調(diào)用匹配一個和弦,那么至少有一個和弦最終會運行。為此,我們增加額外的共享狀態(tài): T(),我們不接受新的讀者,idleExclusive(),在我們所提供的獨占鎖以前選擇主題: 10 class ReaderWriterFair { } . . . // same content as in ReaderWriterPrivate, plus: public void ReleaseShared() amp。 async s() { t()。例如,回調(diào)使用一個字符串參數(shù),服務(wù)代表,并返回一個整數(shù),看起來類似于: public delegate async IntCallback(int result)。這可以編程如下: class Join2 { public IntCallback ?rstcb。 } public void wait(out int i, out int j ) amp。 } } class Client { public static void Main(string[] args) { Service s1 = . . . 。 (args[1], x . secondcb)。一旦發(fā)生這種情況,兩結(jié)果將被分配到 i 和 j,客戶端將繼續(xù)進行。 Detlefs et al. 1998。 Reppy 1992。 they are declared by using the async keyword instead of void. Calling an asynchronous method is much like sending a message, or posting an event. Since asynchronous methods have to return immediately, the behaviour of a method such as async postEvent(EventInfo data) { // large method body } is the only thing it could reasonably be: the call returns immediately and ?large method body? is scheduled for execution in a different thread (either a new one spawned to service this call, or a worker from some pool). However, this kind of de?nition is actually rather rare in Polyphonic C . More monly, asynchronous methods are de?ned using chords, as described below, and do not necessarily require new threads. Chords. A chord (also called a ?synchronization pattern?, or ?join pattern?) consists of a header and a body. The header is a set of method declarations separated by ?amp。 buff . Put(“blue”)。 this is an allowable implementation. ACM Transactions on Programming Languages and Systems, Vol. 26, No. 5, September 2020 (. all the methods in the chord are asynchronous) does the body run in a new thread, and in that case there is no value to be returned. It should also be pointed out that the Buffer code, trivial though it is, is threadsafe. The locking that is required (for example to prevent the argument to a single Put being returned to two distinct Gets) is generated automatically by the piler. More precisely, deciding whether any chord is enabled by a call and, if so, removing the other pending calls from the queues and scheduling the body for execution, is an atomic operation. Apart from this atomicity guarantee, however, there is no monitor like mutual exclusion between chord bodies. Any mutual exclusion that is required must be explicitly programmed in terms of synchronization conditions in chord headers. The Buffer example uses a single chord to de?ne two methods. It is also possible (and mon) to have multiple chords involving a given method. For example: public class Buffer { public string Get() amp。 } } Now we have de?ned one method for getting data out of the buffer, but two methods for putting it in (which happen to be distinguished by type rather than name). A call to Get() can synchronize with a call to either of the Put() methods. If there are queued calls to both P ut()s, then which one synchronizes with a subsequent Get() is unspeci?ed. 3. INFORMAL SPECIFICATION Grammar The syntactic extensions to the C grammar [ECMA 2020, Appendix C] are very minor. We add a new keyword, async, and add it as an alternative return type: returntype : := type | void | async. This allows methods, delegates and interface methods to be declared asynchronous. In class member declarations, we replace method declaration with chord declaration: chorddeclaration : := Methodheader [amp。 virtual async h() { /? body2 ?/ } } } class D : C { override async g () { /? body3 ?/ } one would, by overriding g (), have also ?half ? overridden f (). More pragmatically, removing the restriction on inheritance makes it all too easy to introduce inadvertent deadlock (or ?async leakage?). If the above code were legal, then code writ。 when methods are overridden, all their chords must also be pletely overridden. If one takes the view that the implementation of a given method consists of all the synchronization and bodies of all the chords in which it appears then our inheritance restriction seems not unreasonable, since in (illegal) 4Neither ref nor out parameters make sense for asynchronous messages, since they are both passed as addresses of locals in a stack frame that may have disappeared when the message is processed. 5In C , methods that are intended to be overridable in subclasses are explicitly marked as such by use of the virtual modi?er, while methods that are intended to override ones inherited from a superclass must explicitly say so with the override modi?er. code such as class C { virtual void f () amp。 } public string Get() amp。 (buff . Get() + buff . Get())。 public async Put(string s) { return s。 Philippsen 1995], only monitors have gained widespread acceptance as programming constructs. An interesting new linguistic approach has emerged recently with Four and Gonthier?s [1996, 2020] join calculus, a process calculus well suited to direct implementation in a distributed setting. Other languages, such