Skip to content

Instantly share code, notes, and snippets.

INTRODUCTION:

Remote Procedure Call (RPC) is based on the observation that procedure calls are a well-known and well-understood mechanism for transfer of control within a program running on a single computer.

It is proposed that this same mechanism be extended to provide for transfer of control and data across a communication network. RPC Makes the programming of distributed systems look similar, if not identical, to conventional programming - achieving high level of distribution transparency.

RPC CALL SEMANTICS:

Request-reply protocols can be implemented in different ways to provide different delivery guarantees. The main choices are:

@Phoenix009
Phoenix009 / programming_with_threads.md
Created July 9, 2023 17:09
Programming with threads - Introduction

Introduction:

A "thread" is a straightforward concept: a single sequential flow of control. Having multiple threads in a program means that at any instant the program has multiple points of execution.

The programmer can mostly view the threads as executing simultaneously, as if the computer were endowed with as many processors as there are threads. The programmer must be aware that the computer might not in fact execute all his threads simultaneously.

Each thread executes on a separate call stack with its own separate local variables while the off-stack (global) variables being shared among all the threads of the program. The programmer is responsible for using appropriate synchronisation mechanisms to ensure that the shared memory is accessed in a manner that will give the correct answer.

A thread facility allows us to write programs with multiple simultaneous points of execution, synchronising through shared memory. In this article we discuss the basic thread and synchronisation primitives.

Why u

def traverse(self):
curr_node = self.head
while curr_node:
yield curr_node
curr_node = curr_node.next
def __getitem__(self, index):
if index >= self.length or index < 0: raise IndexError()
it = self.traverse()
def pop_index(self, index):
if index < 0 or index >= self.length:
raise IndexError()
if index == 0:
self.pop_front()
return
curr_node = self.head
for i in range(index-1): curr_node = curr_node.next
def pop_end(self):
if not self.head:
raise IndexError()
if not self.head.next: self.head = None
curr_node = self.head
while curr_node.next.next: curr_node = curr_node.next
curr_node.next = None
self.length -= 1
def pop_front(self):
if not self.head:
raise IndexError()
self.head = self.head.next
self.length -= 1
def insert_index(self, data, index):
index = min(index, self.length)
if index == 0:
self.insert_front(data)
return
new_node = Node(data)
curr_node = self.head
def insert_end(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
else:
curr_node = self.head
while curr_node.next: curr_node = curr_node.next
curr_node.next = new_node
self.length += 1
def insert_front(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
else:
new_node.next = self.head # Step 1
self.head = new_node # Step 2
self.length += 1
class Node:
def __init__(self, data):
self.data = data
self.next = None
class SinglyLinkedList:
def __init__(self):
self.head = None
self.length = 0