yonilipman, danielle.kut Yonatan Lipman (305629750), Danielle Kutner (204094460) EX: 2 FILES: README -- this file uthreads.cpp -- implementation of the thread library Thread.cpp -- implementation of the Thread class methods Thread.h -- Thread Class header REMARKS: We decided to implement the library's data structures in separate structures that act as follows keeping in mind that they all work in FIFO: Ready queue is a deque Blocked and sleeping threads are vectors that act as queues. We also use a min-heap in order to manage the thread id's which is implemented using a priority_queue. This allows us to manage the threads that share the same state in an easy to access manner. We have also thought about holding all of the threads in a single dast but we decided that it was redundant and complex - thus the modular approach was chosen. ANSWERS: 1) Google Chrome creates a new process to have each tab run independently from each other, such that if one process is blocked or runs into some problem, the other tabs (processes) wont be affected by it. We can achieve a similar benefit by running all of the tabs on one process, but splitting them into independent kernel level threads, such that the operating system would manage the threads context switch and if one thread (tab) runs into some problem, it would not affect the other threads. Another benefit that process share with kernel level threads is that both can enjoy the utilization of multi-core Processors. Advantages of creating new process (instead of kernel level threads): * Processes have more resources (e.g memory) * Processes can create multi-threads inside each process in order to calculate tasks faster * Stability - Failure in one process wont lead to failure in other processes Disadvantages of creating new process (instead of kernel level threads): * Requires more resources than threads * Process Context switch has larger overhead than thread context switch. 2) The shell's kill command invokes the kill() system call, which sends signal(s) to the process referenced by its PID via interrupt made by the operating system. The signals that could be send by the kill command are: SIGTERM (default signal sent) SIGKILL we can choose which would be sent by adding a flag to the kill command. SIGKILL cannot be caught by a processes signal handler, such that this signal will kill the process without any consideration regarding the processes state. SIGTERM on the other hand, can be intercepted by a processes signal handler which could invoke useful cleanup operation such as saving information into a file), thus is more common in order to allow processes to handle their forced termination. Writing on the keyboard invokes constant interrupts which interprets what is typed to the shell (process). when the kill command is invoked in the shell, it invokes the system call kill() as mentioned above. By simply using kill without flags, sends the SIGTERM signal which allows the application to handle its forced termination as mentioned above. 3) The difference between 'real' and 'virtual' time, is that 'real' time is continuous and is counted in every process, while 'virtual' time is counted only in the duration of the process's active computation time. 'Real' time example: the OS's clock application utilizes a 'real' time timer the keeps counting no which process is currently active. 'Virtual' time example: when we want to mesaure the runtime of a single process in order to analyze its own running time. e.g the round robin scheduling algorithm utilizes virtual time in order to give each thread a uniform running time. 4) a) Fork duplicates the parent process's environment into the child process up until the command where fork was invoked. Fork uses Copy on Write, such that each process (parent and children) share the same memory resources(stack, heap and global variables) until one of them writes onto the requested memory, invoking an independent copy of the memory. from this moment their resources arent shared and they remain independent. b) Pipe is an inter-process communication channel, which receives 2 fd's that act as read and write, and allows to write from one process into another process which will read the data. By default, the fd's are STDIN and STDOUT, but this could be changed for piping between different independent processes. It is needed because different processes dont share the same memory and this allows them to communicate with each other.