0% found this document useful (0 votes)
18 views

Distributed System Lab

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Distributed System Lab

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Khwaja Moinuddin Chishti Language University

(Uttar Pradesh State Government University)


Lucknow, Uttar Pradesh, India

Faculty of Engineering and Technology

LAB MANUAL FILE 2024-25


Bachelor of Technology,
Computer Science & Engineering

7th Semester

DISTRIBUTED SYSTEM LAB (CS751)

SUBMITTED TO

Mr. Tasleem Jamal


Assistant Professor
Department of Computer Science and Engineering

Submitted By: …………………………………………..

Roll Number: ………………………


Enrollment Number: ……………..
Index
Sr. No Topic Page No. Remark

1 Write a program which simulates client server


communication.

2. Implementing various Interprocess communication


tools in Unix.

3. Implement RPC.

4. Implement RMI.

5. Implement Cristian’s method for synchronizing


clocks.

6. Implement Berkeley algorithm Clock for


synchronizing clocks.

7. Simulate Lamport logical clocks for ordering events.

8. Simulate Mattern and Fidge vector clocks for ordering


events.

9. Detect whether there is a Dead lock in a given wait for


graph.

10. Simulate forward or backward validation technique in


concurrency control.
Experiment 1

Problem Statement: Write a program which simulates client server communication.


Answer: We can implement Client Server Communication as follows in C

Client-Side Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main()
{
int client_socket;
struct sockaddr_in server_address;
// Create socket
if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address struct
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); // Connect to
localhost
server_address.sin_port = htons(PORT);
// Connect to server
if (connect(client_socket, (struct sockaddr *)&server_address,
sizeof(server_address)) == -1)
{
perror("Error connecting to server");
exit(EXIT_FAILURE);
}
printf("Connected to server on port %d\n", PORT);
// Communication with server
char buffer[BUFFER_SIZE];
int bytes_received;
while (1)
{
// Get user input
printf("Enter message (type 'exit' to quit): ");
fgets(buffer, BUFFER_SIZE, stdin);
// Send data to server
send(client_socket, buffer, strlen(buffer), 0);
if (strcmp(buffer, "exit\n") == 0)
{
break;
}
// Receive response from server
bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
if (bytes_received <= 0)
{
perror("Error receiving data");
break;
}
buffer[bytes_received] = '\0'; // Null-terminate the received data
// Print received data
printf("Received from server: %s\n", buffer);
}
// Close socket
close(client_socket);
return 0;
}

Server-Side Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main()
{
int server_socket, client_socket;
struct sockaddr_in server_address, client_address;
socklen_t client_address_len = sizeof(client_address);
// Create socket
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address struct
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(PORT);
// Bind the socket
if (bind(server_socket, (struct sockaddr *)&server_address,
sizeof(server_address)) == -1)
{
perror("Error binding");
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if (listen(server_socket, 5) == -1)
{
perror("Error listening");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// Accept connection from client
if ((client_socket = accept(server_socket, (struct sockaddr
*)&client_address, &client_address_len)) == -1)
{
perror("Error accepting connection");
exit(EXIT_FAILURE);
}
printf("Connection accepted from %s:%d\n",
inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));
// Communication with client
char buffer[BUFFER_SIZE];
int bytes_received;
while (1)
{
// Receive data from client
bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
if (bytes_received <= 0)
{
perror("Error receiving data");
break;
}
buffer[bytes_received] = '\0'; // Null-terminate the received data
// Print received data
printf("Received from client: %s\n", buffer);
// Send a response to the client
send(client_socket, buffer, strlen(buffer), 0);
}
// Close sockets
close(client_socket);
close(server_socket);
return 0;
}

Output
Experiment 2

Problem Statement: Implementing various Interprocess communication tools in Unix.


Answer: Following are the various Interprocess communication tools in Unix along with
their implementation in C Language

a. Pipes
// Pipes allow communication between two related processes.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pipe_fd[2];
char buffer[20];
if (pipe(pipe_fd) == -1)
{
perror("Pipe creation failed");
return 1;
}
pid_t pid = fork();
if (pid == -1)
{
perror("Fork failed");
return 1;
}
if (pid == 0)
{
close(pipe_fd[1]);
read(pipe_fd[0], buffer, sizeof(buffer));
printf("Child received: %s\n", buffer);
close(pipe_fd[0]);
}
else
{
close(pipe_fd[0]);
write(pipe_fd[1], "Hello from parent", 17);
close(pipe_fd[1]);
}
return 0;
}
Output

b. Shared Memory

// Shared memory allows processes to share a region of memory.


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
key_t key;
int shmid;
char *shared_memory;
// Generate a unique key
key = ftok("shm_example", 'A');
// Create shared memory
shmid = shmget(key, 1024, 0666 | IPC_CREAT);
// Attach shared memory
shared_memory = shmat(shmid, NULL, 0);
// Write to shared memory
sprintf(shared_memory, "Hello from shared memory");
// Detach shared memory
shmdt(shared_memory);
// Attach again to read from shared memory
shared_memory = shmat(shmid, NULL, 0);
printf("Shared memory contains: %s\n", shared_memory);
// Detach shared memory
shmdt(shared_memory);
// Remove shared memory
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
Output
c. Message Queues

// Message queues allow processes to communicate by passing messages.


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct message
{
long msg_type;
char msg_text[100];
};
int main()
{
key_t key;
int msgid;
// Generate a unique key
key = ftok("msgq_example", 'A');
// Create a message queue
msgid = msgget(key, 0666 | IPC_CREAT);
struct message msg;
// Send a message
msg.msg_type = 1;
sprintf(msg.msg_text, "Hello from message queue");
msgsnd(msgid, &msg, sizeof(msg), 0);
// Receive a message
msgrcv(msgid, &msg, sizeof(msg), 1, 0);
printf("Received message: %s\n", msg.msg_text);
// Remove the message queue
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
Output
d. Semaphores

// Semaphores are used for synchronization between processes.


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
int main()
{
key_t key;
int semid;
struct sembuf sem_op;
// Generate a unique key
key = ftok("sem_example", 'A');
// Create a semaphore set
semid = semget(key, 1, IPC_CREAT | 0666);
if (semid == -1)
{
perror("Error creating semaphore");
exit(EXIT_FAILURE);
}
// Initialize the semaphore
semctl(semid, 0, SETVAL, 1);
printf("Semaphore initialized to 1\n");
// Perform semaphore operations (wait and signal)
sem_op.sem_num = 0;
sem_op.sem_op = -1; // Wait
sem_op.sem_flg = 0;
printf("Attempting to enter the critical section...\n");
semop(semid, &sem_op, 1); // Wait
printf("Entered the critical section\n");
// Critical section (protected by semaphore)
// Simulate some processing time within the critical section
sleep(2);
printf("Exiting the critical section\n");
sem_op.sem_op = 1; // Signal
semop(semid, &sem_op, 1); // Signal
printf("Semaphore value incremented. Exiting the program.\n");
// Remove the semaphore set
if (semctl(semid, 0, IPC_RMID) == -1)
{
perror("Error removing semaphore");
exit(EXIT_FAILURE);
}
return 0;
}
Output

e. Sockets
// Sockets provide communication between processes over a network. For
interprocess //communication on the same machine, Unix domain sockets are
commonly used.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
int main()
{
int server_socket, client_socket;
socklen_t server_len, client_len;
struct sockaddr_un server_address, client_address;
// Create a socket
server_socket = socket(AF_UNIX, SOCK_STREAM, 0);
// Set up the server address
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "ipc_socket");
server_len = sizeof(server_address);
// Bind the socket to a name
bind(server_socket, (struct sockaddr *)&server_address, server_len);
// Listen for connections
listen(server_socket, 5);
// Accept a connection
printf("Server waiting for a connection...\n");
client_len = sizeof(client_address);
client_socket = accept(server_socket, (struct sockaddr *)&client_address,
&client_len);
printf("Server accepted a connection.\n");
// Communicate with the client (send and receive data)
// Close sockets
close(client_socket);
close(server_socket);
// Remove the socket file
unlink("ipc_socket");
return 0;
}
Output
Experiment 3

Problem Statement: Implement RPC.


Answer: RPC or Remote Procedure Call is when a computer program causes a procedure
(subroutine) to execute in a different address space (commonly on another computer on a
shared network), which is written as if it were a normal (local) procedure call, without the
programmer explicitly writing the details for the remote interaction.
We Can implement RPC in C as follows
Client-Side Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main()
{
int client_socket;
struct sockaddr_in server_addr;
// Create socket
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// Connect to the server
if (connect(client_socket, (struct sockaddr *)&server_addr,
sizeof(server_addr)) == -1)
{
perror("Error connecting to server");
close(client_socket);
exit(EXIT_FAILURE);
}
printf("Connected to server\n");
// Send operation code to the server
int operation = 1; // 1 for addition
send(client_socket, &operation, sizeof(operation), 0);
if (operation == 1)
{ // Addition
// Send data to the server
int a = 3, b = 4;
send(client_socket, &a, sizeof(a), 0);
send(client_socket, &b, sizeof(b), 0);
// Receive the result from the server
int result;
recv(client_socket, &result, sizeof(result), 0);
printf("Result received from server: %d\n", result);
}
// Close the socket
close(client_socket);
return 0;
}

Server-Side Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
// Remote procedure: Addition
int add(int a, int b)
{
return a + b;
}
int main()
{
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
// Create socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = INADDR_ANY;
// Bind the socket
if (bind(server_socket, (struct sockaddr *)&server_addr,
sizeof(server_addr)) == -1)
{
perror("Error binding");
close(server_socket);
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if (listen(server_socket, 5) == -1)
{
perror("Error listening");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("Server listening on port 8888...\n");
// Accept a connection from the client
client_socket = accept(server_socket, (struct sockaddr *)&client_addr,
&client_addr_len);
if (client_socket == -1)
{
perror("Error accepting connection");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("Connection accepted from %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// Receive data from the client
int operation;
recv(client_socket, &operation, sizeof(operation), 0);
if (operation == 1)
{ // Addition
int a, b, result;
recv(client_socket, &a, sizeof(a), 0);
recv(client_socket, &b, sizeof(b), 0);
// Call the remote procedure
result = add(a, b);
// Send the result back to the client
send(client_socket, &result, sizeof(result), 0);
}
// Close sockets
close(client_socket);
close(server_socket);
return 0;
}
Output
Experiment 4

Problem Statement: Implement RMI.


Answer: RMI or Remote Method Invocation is an API that allows an object to invoke a
method on an object that exists in another address space, which could be on the same
machine or on a remote machine. It can be implemented in C in follows.

Client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
// Remote Object definition
typedef struct
{
int value1;
int value2;
} RemoteObject;
int add(int a, int b)
{
return a + b;
}
int main()
{
int client_socket;
struct sockaddr_in server_addr;
// Create socket
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// Connect to the server
if (connect(client_socket, (struct sockaddr *)&server_addr,
sizeof(server_addr)) == -1)
{
perror("Error connecting to server");
close(client_socket);
exit(EXIT_FAILURE);
}
printf("Connected to server\n");
// Receive the remote object from the server
RemoteObject remoteObject;
recv(client_socket, &remoteObject, sizeof(RemoteObject), 0);
// Invoke the remote method
int result = add(remoteObject.value1, remoteObject.value2);
printf("Result of remote method invocation: %d\n", result);
// Close the socket
close(client_socket);
return 0;
}

Server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
// Remote Object definition
typedef struct
{
int (*add)(int, int);
} RemoteObject;
// Remote method implementation
int add(int a, int b)
{
return a + b;
}
int main()
{
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
// Create socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
// Bind the socket
if (bind(server_socket, (struct sockaddr *)&server_addr,
sizeof(server_addr)) == -1)
{
perror("Error binding");
close(server_socket);
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if (listen(server_socket, 5) == -1)
{
perror("Error listening");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// Accept a connection from the client
client_socket = accept(server_socket, (struct sockaddr *)&client_addr,
&client_addr_len);
if (client_socket == -1)
{
perror("Error accepting connection");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("Connection accepted from %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// Initialize the remote object
RemoteObject remoteObject;
remoteObject.add = add;
// Send the remote object to the client
send(client_socket, &remoteObject, sizeof(RemoteObject), 0);
// Close sockets
close(client_socket);
close(server_socket);
return 0;
}
Experiment 5

Problem Statement: Implement Cristian’s method for synchronizing clocks.


Answer: Cristian’s Algorithm is a clock synchronization algorithm is used to synchronize
time with a time server by client processes. We can implement it in C as follows:
Client Side Code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 12345
int main()
{
int clientSocket;
struct sockaddr_in serverAddr;
// Create socket
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;
// Connect to the server
if (connect(clientSocket, (struct sockaddr *)&serverAddr,
sizeof(serverAddr)) == -1)
{
perror("Error connecting to server");
exit(EXIT_FAILURE);
}
// Receive server time
time_t serverTime;
recv(clientSocket, &serverTime, sizeof(serverTime), 0);
// Record local receive time
time_t localReceiveTime;
time(&localReceiveTime);
// Calculate round-trip time
double roundTripTime = difftime(localReceiveTime, serverTime);
// Adjust client clock
time_t adjustedTime = serverTime + (time_t)(roundTripTime / 2.0);
printf("Server Time: %s", ctime(&serverTime));
printf("Round-trip Time: %.2lf seconds\n", roundTripTime);
printf("Adjusted Client Time: %s", ctime(&adjustedTime));
// Close socket
close(clientSocket);
return 0;
}
Server Side Code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 12345
int main()
{
int serverSocket, clientSocket;
struct sockaddr_in serverAddr, clientAddr;
socklen_t addrLen = sizeof(clientAddr);
// Create socket
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;
// Bind socket
if (bind(serverSocket, (struct sockaddr *)&serverAddr,
sizeof(serverAddr)) == -1)
{
perror("Error binding socket");
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if (listen(serverSocket, 5) == -1)
{
perror("Error listening");
exit(EXIT_FAILURE);
}
printf("Server waiting for incoming connections...\n");
// Accept connection from client
clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr,
&addrLen);
if (clientSocket == -1)
{
perror("Error accepting connection");
exit(EXIT_FAILURE);
}
// Get current server time
time_t serverTime;
time(&serverTime);
// Send server time to the client
send(clientSocket, &serverTime, sizeof(serverTime), 0);
// Close sockets
close(clientSocket);
close(serverSocket);
return 0;
}
Output
Experiment 6
Problem Statement: Implement Berkeley algorithm Clock for synchronizing clocks.
Answer: The Berkeley algorithm is a method of clock synchronisation in distributed
computing which assumes no machine has an accurate time source. We can implement it
in C as follows:
Client Side
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 12345
int main()
{
int clientSocket;
struct sockaddr_in serverAddr;
// Create socket
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;
// Connect to the server
if (connect(clientSocket, (struct sockaddr *)&serverAddr,
sizeof(serverAddr)) == -1)
{
perror("Error connecting to server");
exit(EXIT_FAILURE);
}
// Get current client time
time_t clientTime;
time(&clientTime);
// Send client time to the server
send(clientSocket, &clientTime, sizeof(clientTime), 0);
// Receive time difference from the server
time_t timeDifference;
recv(clientSocket, &timeDifference, sizeof(timeDifference), 0);
// Adjust client clock
time_t adjustedTime = clientTime + timeDifference;
printf("Client Time: %s", ctime(&clientTime));
printf("Time Difference: %ld seconds\n", timeDifference);
printf("Adjusted Client Time: %s", ctime(&adjustedTime));
// Close socket
close(clientSocket);
return 0;
}
Server Side
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 12345
#define MAX_CLIENTS 5
int main()
{
int serverSocket, clientSockets[MAX_CLIENTS];
struct sockaddr_in serverAddr, clientAddr;
socklen_t addrLen = sizeof(clientAddr);
// Create socket
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1)
{
perror("Error creating socket");
exit(EXIT_FAILURE);
}
// Set up server address structure
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;
// Bind socket
if (bind(serverSocket, (struct sockaddr *)&serverAddr,
sizeof(serverAddr)) == -1)
{
perror("Error binding socket");
exit(EXIT_FAILURE);
}
// Listen for incoming connections
if (listen(serverSocket, MAX_CLIENTS) == -1)
{
perror("Error listening");
exit(EXIT_FAILURE);
}
printf("Server waiting for incoming connections...\n");
// Accept connections from clients
for (int i = 0; i < MAX_CLIENTS; ++i)
{
clientSockets[i] = accept(serverSocket, (struct sockaddr
*)&clientAddr, &addrLen);
if (clientSockets[i] == -1)
{
perror("Error accepting connection");
exit(EXIT_FAILURE);
}
printf("Client %d connected\n", i + 1);
// Get time from the client
time_t clientTime;
recv(clientSockets[i], &clientTime, sizeof(clientTime), 0);
// Calculate time difference
time_t serverTime;
time(&serverTime);
time_t timeDifference = serverTime - clientTime;
// Send time difference to the client
send(clientSockets[i], &timeDifference, sizeof(timeDifference), 0);
// Close the socket for this client
close(clientSockets[i]);
}
// Close the server socket
close(serverSocket);
return 0;
}
Output
Experiment 7

Problem Statement: Simulate Lamport logical clocks for ordering events.


Answer: Lamport logical clocks for ordering events is a procedure to determine the order
of events occurring. We can implement it in C as follows:

#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int process_id;
int timestamp;
} Event;
void updateTimestamp(int *logical_clock, int new_timestamp)
{
*logical_clock = (new_timestamp > *logical_clock) ? new_timestamp + 1 :
*logical_clock + 1;
}
void simulateLamportClocks()
{
int logical_clock_A = 0;
int logical_clock_B = 0;
// Event for Process A
Event event_A1 = {1, logical_clock_A};
printf("Event A1 - Process %d, Logical Clock: %d\n", event_A1.process_id,
event_A1.timestamp);
// Update logical clock for Process A
updateTimestamp(&logical_clock_A, event_A1.timestamp);
// Event for Process B
Event event_B1 = {2, logical_clock_B};
printf("Event B1 - Process %d, Logical Clock: %d\n", event_B1.process_id,
event_B1.timestamp);
// Update logical clock for Process B
updateTimestamp(&logical_clock_B, event_B1.timestamp);
// Event for Process A
Event event_A2 = {1, logical_clock_A};
printf("Event A2 - Process %d, Logical Clock: %d\n", event_A2.process_id,
event_A2.timestamp);
// Update logical clock for Process A
updateTimestamp(&logical_clock_A, event_A2.timestamp);
// Event for Process B
Event event_B2 = {2, logical_clock_B};
printf("Event B2 - Process %d, Logical Clock: %d\n", event_B2.process_id,
event_B2.timestamp);
// Update logical clock for Process B
updateTimestamp(&logical_clock_B, event_B2.timestamp);
}
int main()
{
simulateLamportClocks();
return 0;
}
Experiment 8

Problem Statement: Simulate Mattern and Fidge vector clocks for ordering events.
Answer: Vector Clock is an algorithm that generates partial ordering of events and detects
causality violations in a distributed system. We can implement it in C as follows:
#include <stdio.h>
#include <stdlib.h>
#define NUM_PROCESSES 3
typedef struct
{
int process_id;
int vector_clock[NUM_PROCESSES];
} Event;
void updateVectorClock(int *vector_clock, int process_id, int new_timestamp)
{
vector_clock[process_id] = new_timestamp + 1;
}
void simulateMatternFidgeVectorClocks()
{
int vector_clock_A[NUM_PROCESSES] = {0};
int vector_clock_B[NUM_PROCESSES] = {0};
int vector_clock_C[NUM_PROCESSES] = {0};
// Event for Process A
Event event_A1 = {0, {0}};
printf("Event A1 - Process %d, Vector Clock: [%d, %d, %d]\n",
event_A1.process_id, event_A1.vector_clock[0],
event_A1.vector_clock[1], event_A1.vector_clock[2]);
// Update vector clock for Process A
updateVectorClock(vector_clock_A, event_A1.process_id,
event_A1.vector_clock[0]);
// Event for Process B
Event event_B1 = {1, {0}};
printf("Event B1 - Process %d, Vector Clock: [%d, %d, %d]\n",
event_B1.process_id, event_B1.vector_clock[0],
event_B1.vector_clock[1], event_B1.vector_clock[2]);
// Update vector clock for Process B
updateVectorClock(vector_clock_B, event_B1.process_id,
event_B1.vector_clock[1]);
// Event for Process C
Event event_C1 = {2, {0}};
printf("Event C1 - Process %d, Vector Clock: [%d, %d, %d]\n",
event_C1.process_id, event_C1.vector_clock[0],
event_C1.vector_clock[1], event_C1.vector_clock[2]);
// Update vector clock for Process C
updateVectorClock(vector_clock_C, event_C1.process_id,
event_C1.vector_clock[2]);
Event event_A2 = {0, {0}};
printf("Event A2 - Process %d, Vector Clock: [%d, %d, %d]\n",
event_A2.process_id, event_A2.vector_clock[0],
event_A2.vector_clock[1], event_A2.vector_clock[2]);
// Update vector clock for Process A
updateVectorClock(vector_clock_A, event_A2.process_id,
event_A2.vector_clock[0]);
// Event for Process B
Event event_B2 = {1, {0}};
printf("Event B2 - Process %d, Vector Clock: [%d, %d, %d]\n",
event_B2.process_id, event_B2.vector_clock[0],
event_B2.vector_clock[1], event_B2.vector_clock[2]);
// Update vector clock for Process B
updateVectorClock(vector_clock_B, event_B2.process_id,
event_B2.vector_clock[1]);
// Event for Process C
Event event_C2 = {2, {0}};
printf("Event C2 - Process %d, Vector Clock: [%d, %d, %d]\n",
event_C2.process_id, event_C2.vector_clock[0],
event_C2.vector_clock[1], event_C2.vector_clock[2]);
// Update vector clock for Process C
updateVectorClock(vector_clock_C, event_C2.process_id,
event_C2.vector_clock[2]);
}
int main()
{
simulateMatternFidgeVectorClocks();
return 0;
}
Output

Experiment 9
Problem Statement: Detect whether there is a Dead lock in a given wait for graph.
Answer: Since the maximum out-degree of a node in a WFG for the single resource model
can be 1, the presence of a cycle in the WFG shall indicate that there is a deadlock. We can
implement it in C as follows
#include <stdio.h>
#include <stdlib.h>
#define MAX_PROCESSES 100
// Function to perform DFS
int isCyclicUtil(int graph[MAX_PROCESSES][MAX_PROCESSES], int process, int
visited[MAX_PROCESSES], int recursionStack[MAX_PROCESSES], int numProcesses)
{
if (!visited[process])
{
visited[process] = 1;
recursionStack[process] = 1;
for (int i = 0; i < numProcesses; i++)
{
if (graph[process][i])
{
if (!visited[i] && isCyclicUtil(graph, i, visited,
recursionStack, numProcesses))
{
return 1;
}
else if (recursionStack[i])
{
return 1;
}
}
}
}
recursionStack[process] = 0;
return 0;
}
// Function to check for deadlock using DFS
int isDeadlock(int graph[MAX_PROCESSES][MAX_PROCESSES], int numProcesses)
{
int visited[MAX_PROCESSES] = {0};
int recursionStack[MAX_PROCESSES] = {0};
for (int i = 0; i < numProcesses; i++)
{
if (isCyclicUtil(graph, i, visited, recursionStack, numProcesses))
{
return 1; // Deadlock detected
}
}
return 0; // No deadlock
}
int main()
{
int numProcesses;
printf("Enter the number of processes: ");
scanf("%d", &numProcesses);
int graph[MAX_PROCESSES][MAX_PROCESSES];
printf("Enter the wait-for graph adjacency matrix (1 for edge, 0 for no
edge):\n");
for (int i = 0; i < numProcesses; i++)
{
for (int j = 0; j < numProcesses; j++)
{
scanf("%d", &graph[i][j]);
}
}
if (isDeadlock(graph, numProcesses))
{
printf("Deadlock detected!\n");
}
else
{
printf("No deadlock.\n");
}
return 0;
}
Output

Experiment 10

Problem Statement: Simulate forward or backward validation technique in concurrency


control.
Answer: Forward and backward validation are two techniques used in optimistic
concurrency control. Forward validation compares the read sets of active transactions
with the write set of the committing transaction. Backward validation compares the
read/write sets of the committing transaction with those of transactions that have
already committed. We can implement it in C as follows.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// Data structure to represent a database entry
typedef struct
{
int data;
int version;
} DataEntry;
// Global data array
DataEntry data[2];
// Function to simulate forward validation
bool forwardValidation(int transaction, int readVersion, int writeVersion)
{
if (readVersion < data[transaction].version)
{
printf("Transaction T%d failed forward validation.\n", transaction +
1);
return false;
}
else
{
printf("Transaction T%d passed forward validation.\n", transaction +
1);
data[transaction].version = writeVersion;
return true;
}
}
// Function to simulate backward validation
bool backwardValidation(int transaction, int readVersion, int writeVersion)
{
if (readVersion < data[transaction].version)
{
printf("Transaction T%d failed backward validation.\n", transaction +
1);
return false;
}
else
{
printf("Transaction T%d passed backward validation.\n", transaction +
1);
data[transaction].version = writeVersion;
return true;
}
}
// Function to simulate a transaction
void executeTransaction(int transaction, int newData, int writeVersion)
{
int readVersion = data[transaction].version;
// Simulate forward validation
if (forwardValidation(transaction, readVersion, writeVersion))
{
// Simulate transaction execution
printf("Executing Transaction T%d...\n", transaction + 1);
data[transaction].data = newData;
printf("Transaction T%d completed.\n", transaction + 1);
}
else
{
printf("Transaction T%d aborted due to validation failure.\n",
transaction + 1);
}
}
int main()
{
// Initialize data
data[0].data = 10;
data[0].version = 1;
data[1].data = 20;
data[1].version = 1;
// Simulate transactions
executeTransaction(0, 15, 2); // T1 with new data 15 and version 2
executeTransaction(1, 25, 3); // T2 with new data 25 and version 3
executeTransaction(0, 18, 4); // T1 with new data 18 and version 4
executeTransaction(1, 30, 5); // T2 with new data 30 and version 5
return 0;
}
Output

You might also like