|
| 1 | +/* |
| 2 | +Simulation of Lamport's Logical Clock Syncronization |
| 3 | +Sample Output Simulation : https://www.showterm.io/556636ec7caa4687680c0 |
| 4 | +References : Distributed systems: Principles and Paradigms, Andrew S. Tanenbaum |
| 5 | +
|
| 6 | +The program takes the following input : |
| 7 | + nProcesses : total no. of processes in the system |
| 8 | + nIterations : no. of counter/clock iterations for which the output is generated |
| 9 | + clockConstant : the constant rate by which counter/clock is incremented on each tick |
| 10 | +
|
| 11 | +Output : |
| 12 | +The program randomly generates a message between any two distinct processes in the system on every 3rd iteration. The message is added to a message queue and read by the recipient on the next iteration. Based on the timestamp at which the message was sent and current time on the receiver, clock time of receiver is adjusted if timestamp of message is >= receiver time else left the same. >= because it will take a finite amount of time to send the message always. |
| 13 | +*/ |
| 14 | + |
| 15 | +package main |
| 16 | + |
| 17 | +import ( |
| 18 | + "fmt" //for println,scanf |
| 19 | + "math/rand" //for random number generator |
| 20 | + "time" //for sleep |
| 21 | +) |
| 22 | + |
| 23 | +func main() { |
| 24 | + var nProcesses, nIterations int // Number of processes, Number of iterations |
| 25 | + fmt.Printf("Enter number of Processes and iterations you want to simulate : ") |
| 26 | + _, err := fmt.Scanf("%d %d", &nProcesses, &nIterations) // _ is blank identifier |
| 27 | + if err != nil { |
| 28 | + fmt.Println("Error : " + err.Error()) |
| 29 | + } |
| 30 | + clockTable := [][]int{} //table to store final counter/logical clock values |
| 31 | + var clockConstants []int //slice to store values by which clock are incremented on each iteration |
| 32 | + clockConstants = make([]int, nProcesses, nProcesses) |
| 33 | + |
| 34 | + fmt.Printf("Enter the clock constants for each process : ") //user input for clock constants |
| 35 | + for i := 0; i < nProcesses; i++ { |
| 36 | + _, err := fmt.Scanf("%d", &clockConstants[i]) |
| 37 | + if err != nil { |
| 38 | + fmt.Println("Error : " + err.Error()) |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + var initClock []int |
| 43 | + initClock = make([]int, nProcesses, nProcesses) |
| 44 | + clockTable = append(clockTable, initClock) |
| 45 | + var msgQueue []int //used to queue messages between processes. |
| 46 | + |
| 47 | + //Print 1st iteration |
| 48 | + for i := 0; i < nProcesses; i++ { |
| 49 | + fmt.Printf(" P%d", i) |
| 50 | + } |
| 51 | + fmt.Println() |
| 52 | + for j := 1; j <= nProcesses; j++ { |
| 53 | + fmt.Printf("%4d", clockTable[0][j-1]) |
| 54 | + } |
| 55 | + fmt.Println() |
| 56 | + |
| 57 | + //Print other iterations |
| 58 | + for i := 1; i < nIterations; i++ { //first iteration already passed so start from 2nd |
| 59 | + |
| 60 | + time.Sleep(2000 * time.Millisecond) //sleep to slow the program down |
| 61 | + |
| 62 | + var temp []int |
| 63 | + temp = make([]int, nProcesses, nProcesses) |
| 64 | + for j := 1; j <= nProcesses; j++ { |
| 65 | + temp[j-1] = clockTable[i-1][j-1] + clockConstants[j-1] |
| 66 | + } |
| 67 | + clockTable = append(clockTable, temp) |
| 68 | + /* generate messages to be sent in every 3rd iteration */ |
| 69 | + if (i+1)%3 == 0 { |
| 70 | + var senderID, receiverID int |
| 71 | + r := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) |
| 72 | + senderID = r.Intn(nProcesses) |
| 73 | + receiverID = r.Intn(nProcesses) |
| 74 | + /*if receiver turns out to be same as sender, find new receiver*/ |
| 75 | + for receiverID == senderID { |
| 76 | + receiverID = r.Intn(nProcesses) |
| 77 | + } |
| 78 | + msgQueue = append(msgQueue, senderID, receiverID) // add message to queue |
| 79 | + fmt.Printf("Message sent by P%d to P%d at time t=%d at P1.\n", senderID, receiverID, clockTable[i-1][senderID]) |
| 80 | + } |
| 81 | + for j := 0; j < nProcesses; j++ { //display clock values |
| 82 | + fmt.Printf("%4d", clockTable[i][j]) |
| 83 | + } |
| 84 | + fmt.Println() |
| 85 | + |
| 86 | + for len(msgQueue) >= 2 { |
| 87 | + var senderID, receiverID int = msgQueue[0], msgQueue[1] |
| 88 | + var sendTime, recTime int = clockTable[i-1][senderID], clockTable[i][receiverID] |
| 89 | + if clockTable[i-1][senderID] >= clockTable[i][receiverID] { |
| 90 | + fmt.Printf("Message received by P%d at time=%d. Since %d <= %d , we adjust time from %d to %d.\n", receiverID, recTime, recTime, sendTime, recTime, (sendTime + 1)) |
| 91 | + for j := 0; j < nProcesses; j++ { |
| 92 | + fmt.Printf("%4d", clockTable[i][j]) |
| 93 | + } |
| 94 | + fmt.Printf(" -->") //display changed clock values |
| 95 | + clockTable[i][receiverID] = clockTable[i-1][senderID] + 1 |
| 96 | + for j := 0; j < nProcesses; j++ { |
| 97 | + fmt.Printf("%4d", clockTable[i][j]) |
| 98 | + } |
| 99 | + fmt.Printf("\n") |
| 100 | + |
| 101 | + } else { |
| 102 | + fmt.Printf("Message received by P%d at time=%d. Since %d >= %d , no time adjustment needed.\n", receiverID, recTime, recTime, sendTime) |
| 103 | + for j := 0; j < nProcesses; j++ { |
| 104 | + fmt.Printf("%4d", clockTable[i][j]) |
| 105 | + } |
| 106 | + fmt.Printf(" =") //display clock values without change |
| 107 | + for j := 0; j < nProcesses; j++ { |
| 108 | + fmt.Printf("%4d", clockTable[i][j]) |
| 109 | + } |
| 110 | + fmt.Printf("\n") |
| 111 | + } |
| 112 | + msgQueue = append(msgQueue[:0], msgQueue[2:]...) //remove sender and receiver from msg queue |
| 113 | + time.Sleep(2000 * time.Millisecond) |
| 114 | + } |
| 115 | + } |
| 116 | +} |
0 commit comments