| // declaration & initial values of global variables Enter, Number: array [1..N] of integer = {0}; // logic used by each thread... // where "(a, b) < (c, d)" // means "(a < c) or ((a == c) and (b < d))" Thread(i) { while (true) { Enter [i] = 1; Number[i] = 1 + max(Number[1],...,Number[N]); Enter [i] = 0; for (j=1; j<=N; ++j) { while (Enter[j] != 0) { // wait until thread j receives its number } while ((Number[j]!=0) && ((Number[j],j) < (Number[i],i))) { // wait until threads with smaller numbers // or with the same number, but with higher // priority, finish their work } } // critical section... Number[i] = 0; // non-critical section... } } |
| 1 function Command() { 2 if (!Command.NextID) Command.NextID = 0; 3 this.id = ++Command.NextID; 4 // unsynchronized API 5 this.doit = function(){ alert("DOIT called"); } 6 this.undo = function(){ alert("UNDO called"); } 7 this.redo = function(){ this.doit(); } 8 // synchronized API 9 this.sDoIt = function(){ new Mutex(this,"doit"); } 10 this.sUnDo = function(){ new Mutex(this,"undo"); } 11 this.sReDo = function(){ new Mutex(this,"redo"); } 12 } |
| 1 function Mutex( cmdObject, methodName ) { 2 // define static field and method 3 if (!Mutex.Wait) Mutex.Wait = new Map(); 4 Mutex.SLICE = function( cmdID, startID ) { 5 Mutex.Wait.get(cmdID).attempt( Mutex.Wait.get(startID) ); 6 } 7 // define instance method 8 this.attempt = function( start ) { 9 for (var j=start; j; j=Mutex.Wait.next(j.c.id)) { 10 if (j.enter 11 || (j.number && (j.number < this.number || 12 (j.number == this.number 13 && j.c.id < this.c.id)))) 14 return setTimeout 15 ("Mutex.SLICE("+this.c.id+","+j.c.id+")",10); 16 } 17 //run with exclusive access 18 this.c[ this.methodID ](); 19 //release exclusive access 20 this.number = 0; 21 Mutex.Wait.remove( this.c.id ); 22 } 23 // constructor logic 24 this.c = cmdObject; 25 this.methodID = methodName; 26 //(enter and number are "false" here) 27 Mutex.Wait.add( this.c.id, this ); 28 this.enter = true; 29 this.number = (new Date()).getTime(); 30 this.enter = false; 31 this.attempt( Mutex.Wait.first() ); 32 } |
| function Map() { this.map = new Object(); // Map API this.add = function( k,o ){ this.map[k] = o; } this.remove = function( k ){ delete this.map[k]; } this.get = function( k ){ return k==null ? null : this.map[k]; } this.first = function(){ return this.get( this.nextKey() ); } this.next = function( k ){ return this.get( this.nextKey(k) ); } this.nextKey = function( k ){ for (i in this.map) { if ( !k ) return i; if (k==i) k=null; /*tricky*/ } return null; } } |
| <html> <script language="JavaScript"> function newState(){ if (XMLreq.readyState==4) processReply(); } function requestData(){ ...set up asynchronous XML request... XMLreq.onreadystatechange = newState; ...launch XML request... } function processReply(){ var transformedData = ...process data to HTML... OutputArea.innerHTML = transformedData + "<br>"; } function clearArea(){ OutputArea.innerHTML = "cleared<br>"; } </script> <body onload="requestData();"> <input type="button" value="clear" onclick="clearArea()"> <div id="OutputArea"/> </body> </html> |
| <html> <script src="mutex.js"></script> <script language="JavaScript"> function requestData (){ new Mutex(new RequestDataCmd(),"go"); } function processReply(){ new Mutex(new ProcessReplyCmd(),"go"); } function clearArea (){ new Mutex(new ClearAreaCmd(),"go"); } function newState (){ if (XMLreq.readyState==4) processReply(); } var NEXT_CMD_ID = 0; function RequestDataCmd(){ this.id = ++NEXT_CMD_ID; this.go = function(){ ...set up asynchronous XML request... XMLreq.onreadystatechange = NewState; ...launch XML request... } } function ProcessReplyCmd(){ this.id = ++NEXT_CMD_ID; this.go = function(){ var transformedData = ...process data to HTML... OutputArea.innerHTML = transformedData + "<br>"; } } function ClearAreaCmd(){ this.id = ++NEXT_CMD_ID; this.go = function(){ OutputArea.innerHTML = "cleared<br>"; } } </script> <body onload="requestData();"> <input type="button" value="clear" onclick="clearArea()"> <div id="OutputArea"/> </body> </html> |