Processes and Threads Flashcards
Process
- The thing which represents our work to the system.
- Sometimes referred to as a heavyweight process.
*An instance of a program in execution.
Instance of a Program in Execution.
- May be more than one version of the same program running at the same time. (Hopefully sharing the code.)
Each instance has resource limitations, security information - rights, capabilities etc. - Includes code, data, connections (to files, networks, other processes), access to
devices. - It needs the processor to run.
Two Parts to a Process
- Resources, the things the process owns (may be shared). Also, information about the process.
- What the process is doing - the streams of execution.
* Traditional processes had resources and a single current location. e.g., traditional UNIX.
The resource part is called a task or a job. The location part is commonly called a thread.
* Most operating systems now provide support to keep these parts separate, e.g., Linux, Solaris, Windows, macOS.
Threads
- Sometimes referred to as lightweight processes. A sequence of instructions being
executed when there is no external intervention. - Multiple threads of a process, share the process resources – but have their own thread ID, PC, registers, stack
- Easier to create than a process. They provide a nice encapsulation of a problem within a process rather than multiple processes.
- Easier to switch between threads than between processes.
Typical Uses of Threads
*Splitting work across processors (shared memory multiprocessor, multiple cores)
*Added responsiveness (handle user input while still finishing another
function)
*Controlling and monitoring other threads
*Server applications
*Can help with program abstraction
User-Level (or Green Threads)
- The OS only sees one thread per process.
- The process constructs other threads by user-level library calls or by hand.
- User-level control over starting and stopping threads.
- Usually a request is made to the OS to interrupt the process regularly (an alarm clock) so that the process can schedule another thread.
- The state of threads in the library code does not correspond to the state of the process.
System-Level Threads
- The OS knows about multiple threads per process.
- Threads are constructed and controlled by system calls.
- The system knows the state of each thread.
User-Level Thread Advantages
*Works even if the OS doesn’t support threads.
* Just a normal library procedure call.
* No switch into kernel mode (this saves time).
*Control can be application specific.
*Easier to switch between - saves processor mode changes.
System-Level Thread Advantages
*Each thread can be treated separately.
*A thread blocking in the kernel doesn’t stop all other threads in the same
process.
*On a multiprocessor (including multi-core) different threads can be
scheduled on different processors (only if OS knows about the threads).
Jacketing
- A blocking system call has a user-level jacket.
- The jacket checks to see if the resource is available, e.g., device is free.
- If not another thread is started.
- When the calling thread is scheduled again (by the thread library) it once
again checks the state of the device.
Solaris (versions < 9)
Had both user-level and system-level threads.
Task | Task | Task
⧙ ⧙ ⧙ (User level threads)
∘ ∘ ∘ (Lightweight Processes)
—
⧙ ⧙ ⧙ (Kernel threads)
Kernel
\ | /
—
CPU
Original Linux Threads (Before 2.6)
Thread creation is done through clone() system call.
Clone() - makes a new process
* Shares memory address space, open files (actually descriptors), signal handlers
From one point of view original Linux threads were processes - but they shared
all resources and hence the advantages of threads.
Original LINUX Threads and POSIX
- Can’t be set to schedule threads according to priority within a process
- each thread is scheduled independently across all threads/processes in the system.
- Can’t send a signal to the whole process.
- Ordinary system calls e.g., read, were not cancellation points.
- Starting a new program in one thread doesn’t kill the other threads in the same process.
pthread Programming
POSIX threads or pthreads are used in UNIX type operating systems.
* Use “man pthread_create” to get the manual page SYNOPSIS
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.
* the #include needs to be added to the top of your source file
* going through the parameters
* thread is a pointer to a pthread_t type - this is where information about the thread is
stored, we need this to join to the thread when we wait for it to finish
* attr is a pointer to pthread attributes, to use the default we put NULL
* start_routine is the name of the function which the thread runs
* arg is a pointer to arguments/parameters used by the function</pthread.h>
Making Sure a pthread Has Finished
To keep the compiler happy our thread function must be of the type:
void (start_routine) (void *)
* The start_routine is a pointer to a function. In C this is exactly the same as a function name.
* The function returns a pointer to a void (i.e., it can return a pointer to anything, we can cast it).
* The function accepts one parameter which is also a pointer to a void (i.e., we can make it point to anything).
void *the_function(void *params) {…}
* We run this in a thread by calling
pthread_create(&thread_info, NULL, the_function, (void *)&args)
* Where args is a pointer to the values we want to send to the function, and thread_info is a pthread_t.
pthread_t thread_info;
Thread Function Parameters
- We can only pass one pointer to the thread, so if we need to pass more than one value we normally use a struct and package up the parameters we want to pass.
- Then we pass the address to the struct.
- When the thread function gets called we unpackage the values.
- Before calling
struct values {
int first;
int second;
};
struct values args;
args.first = 34; args.second = 97;
pthread_create(&thread_info, NULL, the_function, (void *)&args); - In the function
void *the_function(void *params) {
struct values args = *(struct values *)params;
// then we can use args.first and args.second
Segmentation Fault
- Each region has its own set of permissions. For example,
the code segment is usually marked as read-only to prevent accidental modification of the program code. - Situation where we may get a segmentation fault:
1. Accessing uninitialized memory
2. Dereferencing a null pointer
3. Stack overflow.
4. Accessing memory outside of its allocated space
Benefits of Memory Mapping
- Efficient use of physical memory - By allowing multiple processes to share the same physical memory, the operating system can use memory more efficiently.
- Protection - Each process has its own virtual memory
space, which provides protection against other processes accessing its memory. - Large address space - Virtual memory allows each process to have a larger virtual address space than is available in
physical memory.
Virtual Memory
Virtual addresses can stored in virtual memory(disk)
Address Translation
Virtual address spaces(pages) can be stored in physical address space(frames).