Title: Processes, Multiprocessing, Multithreading, and Communication
1Processes, Multiprocessing, Multithreading, and
Communication
2Direction
- Introduce program parallelism
- Use Unix/Linux tools to increase execution speed
within a program - Processes
- Threads
3Process Objectives
- Define process
- Outline ready-execute-wait process cycle
- Define context-switch
- List state saved/restored on context-switch
- Differentiate between short-term and long-term
process scheduling - List three process-scheduling algorithms
- Show in words, and diagram(s) how process
scheduling can induce fragmentation - Compare and contrast process scheduling and
dynamic memory allocation
4Process
- A program in execution
- A process is an instance of an executing program.
It incorporates program code, data used by the
program, the stack, etc. - Several processes can concurrently run the same
program. - Processes can also start other processes.
- UNIX provides a suite of functions to enable the
program to manage these activities.
5But,
- What does it mean to be in execution?
6Process States
New
Terminated
Ready
Running
Waiting
7What to keep track of?
8Process Control Block
Process Number
Program Counter
Registers
Scheduling Info
Memory Limits
I/O Status Info
Accounting Info
9Process Scheduling
- Choose processes for execution (ready Q)
- Decide which process goes from ready to running
10Context Switch
- Change running process
- Move info from running job to PCB?
- Move info for new job from PCB into registers, PC
etc. - Typical time about 1?sec
11Types of Schedulers
- Short term
- CPU Scheduler
- Selects from ready Q
- Runs every few milliseconds
- Must be quick/small
- Long term scheduler
- Controls degree of multiprogramming
- Must balance between CPU-bound and I/O-bound
processes - Decide what goes into ready Q?
12Scheduling Algorithms
- Metrics
- CPU utilization ()
- Throughput
- Processes completed per unit time
- Turnaround time
- Submission to completion
- Waiting time
- Time in ready queue
- Response time
- Interactive systems
13Scheduling Algorithms
- First-Come, First-Served
- Shortest-Job-First
- Priority
- Round-Robin
- Multilevel Queue
14First-Come, First-Served
- Non-preemptive
- Process must voluntarily relinquish by
terminating or by making a system call - Intrinsic priority Arrival time
- Expected performance ?
- Limitations ?
- Benefits ?
15Shortest-Job-First
- Non-preemptive
- Better response for short jobs
- Provably optimal
- min avg. waiting time for a pool of jobs
- Disadvantage(s) ?
16Priority
- Associate priority with each process
- One queue for each priority level
- FCFS within each level
- Problem(s) with priority?
- SJF is special case
17Priority
- Starvation possible
- Solution?
- Increase priority with age
- Implement aging ?
- Nice (Unix)
18Round-Robin
- Preemptive
- Process runs time-slice (q) units
- FCFS special case of RR (q infinity)
- Time sharing
- Each process executes at speed 1/n.
- q ???
- Balance q with context switch time
19Multilevel Queues
- Partition Ready Queue
- Each Q has own schedule method
- E.g. foreground (interactive, RR) and background
(batch, FCFS) queues - Approaches
- Higher queues have absolute priority over lower
level queues OR - Time slice among queues
20Evaluation
- Modeling
- Deterministic - Requires exact numbers
- Queuing - Uses distribution of bursts
- Simulation
- Create software models of systems.
- Lots of work
- Very time consuming
- Actual implementation test
- Cost
- May change behavior
21What is a Thread?
- A thread is
- An abstraction of a process activity
- An active sequence of instructions in a process
- A process activity is defined by its context
- Program counter Tells which instruction is being
executed - Stack Determines where in the program we are
(e.g. which function, what parameters)
22Process
- Process is an abstraction of a program
- A process has a single thread of activity
- Single program counter, stack
- Code, data, heap
- How do processes communicate?
- Shared memory, sockets, signals
- Require significant OS support
23Threads
- Threads exist within a process
- Threads share process code, data, heap
- Each thread has its own program counter, stack
- Multiple threads may run concurrently within the
same process! - How do threads communicate? process memory
24Process vs. Threads
Process
Threads
Data
Code
Heap
Data
Code
Heap
PC
PC
PC
PC
Stack
Stack
Stack
Stack
25Thread Benefits
- Efficiency
- Thread operation cheaper than processes
- Shorter context switch
- Concurrency
- One thread blocks, another can run
- Make use of parallel hardware
- Resource Sharing
- Threads share resources of the process
- Less OS resource use
26Thread Problems
- Programming Complexity
- Non-deterministic behavior
- Need to be synchronized
- Difficult to debug (usually)
- Portability problems due to different
implementations
27The fork( ) Facility
- int fork ( )
- fork( ) returns an integer value called the
process-id of the newly created process. - fork( ) is the basic process creation primitive.
It creates a new process by duplicating the
calling process. The new process is often called
the child process, while the one initiating the
fork is called the parent.
28fork ( ) Example
- / forktest -- demonstrates fork /
- int main (void)
-
- int pid
- printf (Start of test\n)
- printf (Calling fork ...\n)
- pid fork( )
- printf (Returned d\n, pid)
29The exec( ) Family
- char path, file
- char arg0, arg1, ..., argn
- char argv
- int ret
- ret execl (path, arg0, arg1, ... , argn, (char
)0) - ret execv (path, argv)
- ret execlp (file, arg0, arg1, ... , argn, (char
) 0) - ret execvp (file, argv)
30execl( ) Example
- / exectest -- use execl t/
- int main (void)
-
- printf (The quick brown fox jumped over\n)
- execl (/bin/echo, echo, the, lazy,
dogs, NULL) - perror (execl failed)
- exit(1)
31execv( ) Example
- / runls - use execv to run ls /
- int main (void)
-
- char av3
- av0 ls
- av1 -l
- av2 (char )0
- execv(/bin/ls, av)
-
- perror (execv failed)
- exit(1)
32exec( ) and fork( ) Together
- / runls2 -- run ls in a subprocess /
- int main (void)
-
- int pid
- pid fork( )
- if (pid gt 0)
-
- wait ( (int ) 0)
- printf (ls completed\n)
- exit(0)
-
- if ( pid 0)
-
- execl (/bin/ls, ls, -l, (char ) 0)
- fatal (execl failed)
-
- fatal (fork failed)
33exec( ) and fork( ) Together
- fatal (char s)
-
- perror (s)
- exit (1)
34Inherited Data and File Descriptors
- A child process created with a fork( ) is almost
a perfect copy of the parent, including copies of
all the current values of the variables and all
the open file descriptors. - Changing the value of variables in one process
will not affect the value in the other, since
each process has its own data space. - However, changing the position of the read/write
pointer for a file copied across a fork( ) will
affect the position of the file pointer in the
other process.
35Inherited Data and File Descriptors
- Open file descriptors are also passed across
calls to exec( ). - However, the fcntl( ) function can be used to set
the close-on-exec flag associated with a
particular file. In this case, the file is
automatically when an exec( ) call is invoked.
36Inherited Data and File Descriptors - Example
- / proc_file /
- include ltfcntl.hgt
- int main (void)
-
- int fd, pid
- char buf10
- if ( (fd open (data, O_RDONLY)) lt 0)
- fatal (open failed)
- read (fd, buf, 10)
- printpos (Before fork, fd)
- if (pid fork( )) lt 0)
- fatal (fork failed)
-
- else if ( pid 0 )
-
- printpos (Child before read, fd)
- read (fd, buf, 10)
- printpos (Child after read, fd)
-
37Inherited Data and File Descriptors - Example
- else
-
- wait ( (int ) 0)
- printpos (Parent after wait, fd)
-
-
- printpos (char string, int filedes)
-
- long pos, lseek( )
- if ( pos lseek(filedes, 0L, 1)) lt 0L)
- fatal (lseek failed)
- printf (sld\n, string, pos)
-
38Inherited Data and File DescriptorsAnother
Example
- include ltfcntl.hgt
- .
- .
- int fd
- fd open (file, O_RDONLY)
- .
- .
- fcntl (fd, F_SETFD, 1)
- The close-on-exec flag can be turned off with
- fcntl ( fd, F_SETFD, 0)
39exit( )
- exit ( int status)
- exit( ) is used to terminate a process. It closes
all open file descriptors and returns the status
value to the parent process. If the parent
executed a wait( ), this will reactivate the
parent. exit( ) is one of the few functions that
does not return to the caller.
40wait( )
- int wait (int status)
- wait( ) temporarily suspends the execution of a
process while a child process is running. When
the child process terminates, the parent process
resumes. If more than one child is running, wait(
) will return as soon as any one of them
completes. - wait( ) normally returns the process-id of the
exiting child. On an error, wait( ) returns a -1,
usually meaning that no child exists on which to
wait.
41Zombies and Premature Exits
- Zombie processes are created when a child exits
when its parent is not currently executing a
wait( ). The zombie process occupies a slot in
the process table, but does not use any system
resources. It will be cleared out if its parent
finally claims the child by executing a wait( ). - A premature exit occurs when a parent exits while
one or more children are still executing. In this
case, all children, including any that might be
zombies, are adopted by the systems
initialization process.
42Obtaining Process and Group Ids
- A program can obtain its own process id with
- pid getpid( )
- A program can obtain the process id of its parent
with - ppid getppid( )
- A process can change the process group it belongs
to with - newpg setpgrp( )
- A process can obtain its current process group id
with - pgid getpgrp( )
43Group Id Example
- / remain.c -- can live beyond logout /
- int main (void)
-
- int newpgid
- newpgid setpgrp( )
- / body of program goes here /
44Process Priorities
- The UNIX system decides the percentage of CPU
time allocated to each process based on its
integer nice value. The higher the nice number,
the lower the processes priority. - Processes can alter their nice value with the
nice( ) function. Processes can only decrease
their priority, thus increasing their nice value,
unless their effective user id is that of the
superuser. This is done by calling the nice( )
function with a negative value.
45Signals Overview
- Signals are used by the UNIX kernel to signal
severe errors and requests for termination - Signals can also be sent from process to process
- In general, signals provide a simple method for
transmitting software interrupts to UNIX
processes.
46UNIX Signals
- Available signals in UNIX are defined in
ltsignal.hgt. - SIGHUP - The hangup signal, sent upon user
logout - SIGINT - Interrupt signal, sent on break signal
from user - SIGQUIT - Quit signal, sent when user hits quit
key - SIGILL - Illegal Instruction signal
- SIGTRAP - Trace trap signal used by debuggers
- SIGFPE - Floating-Point exception signal
- SIGKILL - Sent from one process to another to
terminate - SIGSYS - Bad argument to a system call signal
- SIGPIPE - Write on a pipe with no one to read
it - SIGALRM - Alarm clock signal used for software
timers - SIGTERM - Software termination signal to
terminate process - SIGUSR1 - user signal
- SIGUSR2 - user signal
- Other implementation-dependent signals also
exist, but are not defined by the UNIX System V
standard.
47Signal Usage
- include ltsignal.hgt
- int func( ), (oldhdlr)( ), sig
- .
- .
- oldhdlr signal (sig, func)
- where sig indicates the signal for which the
handler func is to be installed. The signal call
returns the address of the function that was the
previous handler. func is either a user-supplied
handler, or it can be a standard handler of
types - SIG_IGN - ignore this signal
- SIG_DFL - restore system default handler
48Catching a Signal
- / sigex - - catches the SIGINT signal as an
example / - include ltsignal.hgt
- include ltstdio.hgt
- int main (void)
-
- int sigcatcher( )
- signal (SIGINT, sigcatcher)
- printf (sleep call 1\n)
- sleep(1)
- printf (sleep call 2\n)
- sleep(1)
- printf (sleep call 3\n)
- sleep(1)
- printf (sleep call 4\n)
- sleep(1)
- printf (Exiting\n)
- exit (0)
49Catching a Signal
- int sigcatcher (int signo)
-
- printf (\nSIGCATCHER signo d\n, signo)
- printf (SIGCATCHER returning\n\n)
50Resetting Signals
- / reset -- signals example /
- include ltsignal.hgt
- include ltstdio.hgt
- int interrupt( )
-
- printf (Interrupt called\n)
- sleep(10)
-
- int main(void)
-
- signal (SIGINT, interrupt)
- printf (Interrupt set for SIGINT\n)
- sleep(10)
51A Better Handler
- include ltsignal.hgt
- include ltstdio.hgt
- int interrupt( )
-
- signal( SIGINT, SIG_IGN)
- printf (Interrupt called\n)
- .
- .
- .
- signal (SIGINT, interrupt)
52Sending Signals With kill( )
- int kill (int pid, int sig) where pid is the
process id to send the signal to, and sig is the
interrupt signal to send. The kill function
returns a -1 on error, or a 0 on success. - The pid parameter can also have some special
meanings as follows - pid 0 - the signal will be sent to all
processes that belong to the same process group
as the sender. - pid -1 and the effective user id of the process
is not superuser - signal will be sent to all
processes whose real user id equal to the
effective user id of the sender. - pid -1 and the sender has an effective user id
of superuser - signal will be sent to all
processes with the exception of some special
system processes. - pid lt -1 - signal will be sent to all processes
with a process group id equal to the absolute
value of pid.
53kill( ) Example
- / synchro - example for kill /
- include ltsignal.hgt
- include ltstdio.hgt
- int ntimes 0
- int main (void)
-
- int pid, ppid
- int p_action( ), c_action( )
-
- signal (SIGUSR1, p_action)
- switch (pid fork( ))
-
- case -1
- perror( synchro)
- exit(1)
- case 0
- signal(SIGUSR1, c_action)
- ppid getppid( )
54kill( ) Example
- for ( )
-
- sleep(1)
- kill( ppid, SIGUSR1)
- pause( )
-
- default
- for ( )
-
- pause( )
- sleep(1)
- kill( pid, SIGUSR1)
-
-
-
55kill( ) Example
- p_action( )
-
- printf( Parent caught signal d\n,
ntimes) - signal( SIGUSR1, p_action)
-
- c_action( )
-
- printf( Child caught signal d\n, ntimes)
- signal( SIGUSR1, c_action)
56Using alarm( )
- unsigned int alarm (unsigned int secs)
- secs specifies the time in seconds until the
alarm. When the time expires, the process will be
sent a SIGALRM. - alarm () returns the time remaining for any
previously set timer. - Note that alarm( ) calls cannot be stacked. That
is, two successive calls to alarm will result in
the second call superseding the first. - alarm(0) will turn off a previously set timer.
57alarm( ) Example
- include ltstdio.hgt
- include ltsignal.hgt
- define TIMEOUT 5
- define MAXTRIES 5
- define LINESIZE 100
- define CTRL_G \007
- define TRUE 1
- define FALSE 0
- static int timed_out
- static char inlineLINESIZE
- extern char gets( )
- char quickreply( char prompt)
-
- int (prev)( ), catch( ), ntries
- char answer
- prev signal( SIGALRM, catch)
58alarm( ) Example
- for (ntries 0 ntries lt MAXTRIES ntries)
-
- timed_out FALSE
- printf (\ns gt , prompt)
- alarm (TIMEOUT)
- answer gets( inline)
- alarm(0)
- if (!timed_out) break
-
- signal( SIGALRM, prev)
-
- return (ntries MAXTRIES ? ((char )0)
answer) -
- catch( )
-
- timed_out TRUE
- putchar (CTRL_G)
- signal (SIGALRM, catch)
-
59pause( )
- int pause( )
- pause( ) suspends the calling process, without
wasting resources, until some kind of signal is
received.
60pause( ) Example
- / tml -- tell-me-later program /
- include lt stdio.hgt
- include ltsignal.hgt
- define TRUE 1
- define FALSE 0
- define BELLS \007\007\007
- int alarm_flag FALSE
- setflag( )
- alarm_flag TRUE
- int main (int argc, char argv )
-
- int nsecs, pid
- int j
- if (argc lt 2)
-
- fprintf( stderr, Usage tml minutes
message\n) - exit(1)
-
61pause( ) Example
- if ((nsecs atoi(argv160) lt 0)
-
- fprintf(stderr, tml invalid time\n)
- exit(2)
-
- switch(pid fork( ))
-
- case -1
- perror(tml)
- exit(1)
-
- case 0
- break
- default
- printf(tml process-id d\n, pid)
- exit(0)
-
- signal(SIGALRM, setflag)
- alarm(nsecs)
- pause( )
62pause( ) Example
- if (alarm_flag TRUE)
-
- printf (BELLS)
- for (j 2 j lt argc j)
- printf( s , argvj)
- printf(\n)
-
- exit(0)