0% found this document useful (0 votes)
42 views99 pages

Concurrency

The document discusses concurrency and concurrent programming. Concurrency refers to events happening simultaneously, while concurrent programming involves managing shared resources and context switching between processes. The document contrasts concurrent and parallel programming, and describes benefits and drawbacks of concurrency.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views99 pages

Concurrency

The document discusses concurrency and concurrent programming. Concurrency refers to events happening simultaneously, while concurrent programming involves managing shared resources and context switching between processes. The document contrasts concurrent and parallel programming, and describes benefits and drawbacks of concurrency.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 99

Concurrency, Scheduling and

dispatch
What is concurrent programming?
• Concurrency generally refers to events or circumstances
that are happening or existing at the same time.
• In programming terms, concurrent programming is a
technique in which two or more processes start, run in
an interleaved fashion through context switching and
complete in an overlapping time period by managing
access to shared resources e.g. on a single core of CPU.
• This doesn’t necessarily mean that multiple processes
will be running at the same instant – even if the results
might make it seem like it.
Difference between Concurrent & Parallel
programming
• In parallel programming, parallel processing is
achieved through hardware parallelism e.g.
executing two processes on two separate CPU
cores simultaneously.
• Concurrency is everywhere in modern
programming, whether we like it or not:
 Multiple computers in a network
 Multiple applications running on one computer
 Multiple processors in a computer (today,
often multiple processor cores on a single chip)
Difference …
• In fact, concurrency is essential in modern
programming:
• Web sites must handle multiple simultaneous
users.
• Mobile apps need to do some of their processing
on servers (“in the cloud”).
• Graphical user interfaces almost always require
background work that does not interrupt the
user. For example, Eclipse compiles your Java
code while you’re still editing it.
Why concurrent programing is important?

• Allows multiple applications to run at the same


time
• Processor clock speeds are no longer
increasing.
• Instead, we’re getting more cores with each
new generation of chips.
• So in the future, in order to get a computation
to run faster, we’ll have to split up a
computation into concurrent pieces.
Benefits of Concurrency
 Ability to run multiple applications at the same time
 Better resource utilization
 Resources unused by one application can be used by the
others
 Better average response time
 No need to wait for other applications to complete
 Better performance
 One application uses only the processor
 One application uses only the disk drive
 Completion time is shorter when running both concurrently
than consecutively
Drawbacks of Concurrency
 Applications need to be protected from one another
 Additional coordination mechanisms among applications
 Overhead to switch among applications
 Potential performance degradation when running too
many applications
 Sharing of global resources – coordinated access to
shared resources
 Operating system managing the allocation of resources
optimally – do we know the future behaviour (needed
resources) of processes?
 Difficult to locate programming errors
Potential Problems related to concurrency
management by OS
 In some case multiple process might request shared resource
(read or write I/O) in this case race condition occur
 Which means
 Two processes want to access shared memory at the same
time.
 The final result depends on who runs precisely when.
 This condition leads to
 Data incoherency
 Deadlock: processes are “frozen” because of mutual
dependency on each other
 Starvation: some of the processes are unable to make
progress (i.e., to execute useful code)
Critical Regions

Mutual exclusion using critical regions


Mutual exclusion
Critical region: part of the program where shared
memory is accessed.
Four conditions for correct and efficient communication:
1. Mutual exclusion: No two processes simultaneously in
critical region
2. No assumptions made about speeds or numbers of CPUs
3. Progress: No process running outside its critical region may
block another process
4. Fairness, i.e., no starvation: No process must wait forever
to enter its critical region (assuming fair scheduling!)
Two Models for Concurrent Programming

• There are two common models for concurrent


programming:
• shared memory and
• message passing.
Shared memory
• In the shared memory model of concurrency, concurrent
modules interact by reading and writing shared objects
in memory.
• Other examples of the shared-memory model:

 A and B might be two processors (or processor cores)


in the same computer, sharing the same physical memory.
 A and B might be two programs running on the same computer,
sharing a common file system with files they can read and write.
 A and B might be two threads in the same Java program (we’ll
explain what a thread is below), sharing the same Java objects.
Message passing
• In the message-passing model, concurrent modules interact by
sending messages to each other through a communication
channel.
• Modules send off messages, and incoming messages to each
module are queued up for handling. Examples include:

• A and B might be two computers in a network, communicating by network


connections.
• A and B might be a web browser and a web server – A opens a connection to
B, asks for a web page, and B sends the web page data back to A.
• A and B might be an instant messaging client and server.
• A and B might be two programs running on the same computer whose input
and output have been connected by a pipe, like ls | grep typed into a
command prompt.
• The message-passing and shared-memory
models are about how concurrent modules
communicate.
• The concurrent modules themselves come in
two different kinds: processes and threads.
What is a program?
A program consists of:
– Code: machine instructions
– Data: variables stored and manipulated in memory
• initialized variables (globals)
• dynamically allocated variables (malloc, new)
• stack variables (C automatic variables, function arguments)
– DLLs: libraries that were not compiled or linked with the program
• containing code & data, possibly shared with other programs
– mapped files: memory segments containing variables (mmap())
• used frequently in database programs

• Whats the relationship between a program and process?


– A process is a executing program
Preparing a Program
compiler/
assembler Linker

source .o files
file
static libraries
Header (libc, streams…)

Code

Executable file
Initialized data (must follow standard format,
such as ELF on Linux,
Microsoft PE on Windows)
BSS
Symbol table

Line numbers
Ext. refs
Running a program
• OS creates a “process” and allocates memory for it
• The loader:
– reads and interprets the executable file
– sets process’s memory to contain code & data from executable
– pushes “argc”, “argv”, “envp” on the stack
– sets the CPU registers properly & calls “__start()”
– Program start running at __start(), which calls main()
– we say “process” is running, and no longer think of “program”
• When main() returns, controler calls “exit()”
– destroys the process and returns all resources
Process != Program mapped segments

Header DLL’s
Program is passive
Code • Code + data
Stack
Initialized data Process is running program
• stack, regs, program counter
BSS
Symbol table
Example:
Line numbers Heap
We both run IE:
Ext. refs - Same program BSS
- Separate processes
Executable
Initialized data

Process
address space Code
Process States
• Many processes in system, only one on CPU
• “Execution State” of a process:
– Indicates what it is doing
– Basically 3 states:
• Ready: waiting to be assigned to the CPU
• Running: executing instructions on the CPU
• Waiting: waiting for an event, e.g. I/O completion
• Process moves across different states
Process State Transitions
interrupt

adm
New i tt e Exit
d e
dispatch don
Ready Running

it
wa
I/O omp

t
c

en
or leti

ev
ev on

or
en

Waiting

I/O
t

Processes hop across states as a result of:


• Actions they perform, e.g. system calls
• Actions performed by OS, e.g. rescheduling
• External actions, e.g. I/O
Process Data Structures
• OS represents a process using a PCB
– Process Control Block
– Has all the details of a process

Process Id Security Credentials

Process State Username of owner

General Purpose Registers Queue Pointers

Stack Pointer Signal Masks


Program Counter Memory Management

Accounting Info …
What happens during execution?
Addr 232-1
R0


R31 Data1
Fetch
F0 Data0
… Exec
Inst237
F30
PC Inst236

Inst5
• Execution sequence: Inst4
– Fetch Instruction at PC Inst3 PC
– Decode Inst2 PC
– Execute (possibly using registers) Inst1 PC
– Write Results to registers Inst0 PC
– PC = Next Instruction(PC) Addr 0
– Repeat
How can we give the illusion of multiple processors?

CPU1 CPU2 CPU3


CPU1 CPU2 CPU3 CPU1 CPU2

Shared Memory Time


• How do we provide the illusion of multiple processors?
– Multiplex in time!
• Each virtual “CPU” needs a structure to hold:
– Program Counter (PC)
– Registers (Integer, Floating point, others…?)
• How switch from one CPU to the next?
– Save PC and registers in current state block
– Load PC and registers from new state block
• What triggers switch?
– Timer, voluntary yield, I/O, other things
The Basic Problem of Concurrency
• The basic problem of concurrency involves resources:
– Hardware: single CPU, single DRAM, single I/O devices
– Multiprogramming API: users think they have exclusive
access to machine
• OS Has to coordinate all activity
– Multiple users, I/O interrupts, …
– How can keep this straight?
• Basic Idea: Use Virtual Machine abstraction
– Decompose hard problem into simpler ones
– Abstract the notion of an executing program
– Then, worry about multiplexing these abstract machines
Thread
 A sequential execution stream
 The smallest CPU scheduling unit
 Can be programmed as if it owns the entire CPU

 Implication: an infinite loop within a thread won’t halt the


system
 Illusion of multiple CPUs on a single machine
 Thread states
 Program counter

 Register values

 Execution stacks
Thread Benefits
 Simplified programming model per thread
 Example: Microsoft Word
 One thread for grammar check; one thread for
spelling check; one thread for formatting; and so
on…
 Can be programmed independently

 Simplifies the development of large applications


Address Space
 Contains all states necessary to run a program
 Code, data, stack(s)
 Program counter(s)

 Register values

 Resources required by the program

 Status of the running program


Process
 An address space + at least one thread of
execution
 Address space offers protection among processes
 Threads offer concurrency

 A fundamental unit of computation


Threads & Dispatching Loop
 A thread owns a thread control block
 Execution states of the thread
 The status of the thread

 Running or sleeping
 Scheduling information of the thread
 e.g., priority
Dispatching Loop

 Threads are run from a dispatching


loop
 LOOP
 Run thread
 Save states Jump to the first instruction
Context
switch
 Choose a new thread to run
 Load states from a different thread Scheduling
Simple? Not quite…

 How does the dispatcher regain control after a


thread starts running?
 What states should a thread save?
 How does the dispatcher choose the next
thread?
How does the dispatcher
regain control?
 Two ways:
1. Internal events (“Sleeping Beauty”)
 A thread is waiting for I/O
 A thread is waiting for some other thread
 Yield—a thread gives up CPU voluntarily
2. External events
 Interrupts—a complete disk request
 Timer—it’s like an alarm clock
What states should a thread
save?
 Anything that the next thread may
trash before a context switch
 Program counter
 Registers
 Changes in execution stack
How does the dispatcher
choose the next thread?
 The dispatcher keeps a list of threads
that are ready to run
 If no threads are ready
 Dispatcher just loops
 If one thread is ready
 Easy
How does the dispatcher
choose the next thread?
 If more than one thread are ready
 We choose the next thread based on the
scheduling policies
 Examples
 FIFO (first in, first out)
 LIFO (last in, first out)
 Priority-based policies
Schedulers
• Process migrates among several queues
– Device queue, job queue, ready queue
• Scheduler selects a process to run from these queues
• Long-term scheduler:
– load a job in memory
– Runs infrequently
• Short-term scheduler:
– Select ready process to run on CPU
– Should be fast
• Middle-term scheduler (aka swapper)
– Reduce multiprogramming or memory consumption
Process Scheduling
• “process” and “thread” used interchangeably
• Which process to run next

• Many processes in “ready” state


• Which ready process to pick to run on the CPU?
– 0 ready processes: run idle loop
– 1 ready process: easy!
– > 1 ready process: what to do?

New Ready Running Exit

Waiting
When does scheduler run?
• Non-preemptive minimum
– Process runs until voluntarily relinquish CPU
• process blocks on an event (e.g., I/O or synchronization)
• process terminates
• process yields

• Preemptive minimum
– All of the above, plus:
• Event completes: process moves from blocked to ready
• Timer interrupts
• Implementation: process can be interrupted in favor of another

New Running Exit


Ready

Waiting
Process Model
• Process alternates between CPU and I/O bursts
– CPU-bound jobs: Long CPU bursts

Matrix multiply
– I/O-bound: Short CPU bursts

emacs
emacs
– I/O burst = process idle, switch to another “for free”
– Problem: don’t know job’s type before running
Student Presidential debates in Sunday
• Why watch?
– Want to see what hype is about
– Very entertaining
– See who is going to be elected president
– Support your friend who is computing for the position

• What does the presidential debates have to do with


scheduling?!
– Also, want to watch Football, its championship game, or watch movie,
etc
– But, have to finish Project and Homework! For Monday
– You have to meet your sweet heart for love street walk (its Sunday you
have to if you have one)

– What criteria to use to schedule events?


Scheduling Evaluation Metrics
• Many quantitative criteria for evaluating sched algorithm:
– CPU utilization: percentage of time the CPU is not idle
– Throughput: completed processes per time unit
– Turnaround time: submission to completion
– Waiting time: time spent on the ready queue
– Response time: response latency
– Predictability: variance in any of these measures

• The right metric depends on the context

• An underlying assumption:
– “response time” most important for interactive jobs (I/O bound)
“The perfect CPU scheduler”
• Minimize latency: response or job completion time
• Maximize throughput: Maximize jobs / time.
• Maximize utilization: keep I/O devices busy.
– Recurring theme with OS scheduling
• Fairness: everyone makes progress, no one starves
Problem Cases
• Blindness about job types
– I/O goes idle
• Optimization involves favoring jobs of type “A” over “B”.
– Lots of A’s? B’s starve
• Interactive process trapped behind others.
– Response time sucks for no reason
• Priority Inversion: A depends on B. A’s priority > B’s.
– B never runs
Scheduling Algorithms FCFS
• First-come First-served (FCFS) (FIFO)
– Jobs are scheduled in order of arrival
– Non-preemptive
• Problem:
– Average waiting time depends on arrival order

P1 P2 P3
time
0 16 20 24
P2 P3 P1
0 4 8 24
• Advantage: really simple!
Convoy Effect
• A CPU bound job will hold CPU until done,
– or it causes an I/O burst
• rare occurrence, since the thread is CPU-bound
 long periods where no I/O requests issued, and CPU held
– Result: poor I/O device utilization
• Example: one CPU bound job, many I/O bound
• CPU bound runs (I/O devices idle)
• CPU bound blocks
• I/O bound job(s) run, quickly block on I/O
• CPU bound runs again
• I/O completes
• CPU bound still runs while I/O devices idle (continues…)
– Simple hack: run process whose I/O completed?
• What is a potential problem?
Scheduling Algorithms LIFO
• Last-In First-out (LIFO)
– Newly arrived jobs are placed at head of ready queue
– Improves response time for newly created threads
• Problem:
– May lead to starvation – early processes may never get CPU
Problem
• You work as a short-order cook
– Customers come in and specify which dish they want
– Each dish takes a different amount of time to prepare
• Your goal:
– minimize average time the customers wait for their food
• What strategy would you use ?
– Note: most restaurants use FCFS.
Scheduling Algorithms: SJF
• Shortest Job First (SJF)
– Choose the job with the shortest next CPU burst
– Provably optimal for minimizing average waiting time

P1 P3 P2
0 15 21 24
PP2 2 PP3 3 P1
0 3 9 24
• Problem:
– Impossible to know the length of the next CPU burst
Scheduling Algorithms SRTF
• SJF can be either preemptive or non-preemptive
– New, short job arrives; current process has long time to execute
• Preemptive SJF is called shortest remaining time first
P2

P3 P1
0 6 10 21

P3 P1 P2 P1
0 6 10 13 24
Shortest Job First Prediction
• Approximate next CPU-burst duration
– from the durations of the previous bursts
• The past can be a good predictor of the future
• No need to remember entire past history
• Use exponential average:
tn duration of the nth CPU burst
n+1 predicted duration of the (n+1)st CPU burst
n+1 =  tn + (1- ) n
where 0    1
 determines the weight placed on past behavior
Prediction of the Length of the Next CPU Burst
Examples of Exponential Averaging
•  =0
– n+1 = n
– Recent history does not count
•  =1
– n+1 =  tn
– Only the actual last CPU burst counts
• If we expand the formula, we get:
n+1 =  tn+(1 - ) tn -1 + …
+(1 -  )j  tn -j + …
+(1 -  )n +1 0

• Since both  and (1 - ) are less than or equal to 1, each


successive term has less weight than its predecessor
Priority Scheduling
• Priority Scheduling
– Choose next job based on priority
– For SJF, priority = expected CPU burst
– Can be either preemptive or non-preemptive
• Problem:
– Starvation: jobs can wait indefinitely
• Solution to starvation
– Age processes: increase priority as a function of waiting time
Round Robin
• Round Robin (RR)
– Often used for timesharing
– Ready queue is treated as a circular queue (FIFO)
– Each process is given a time slice called a quantum
– It is run for the quantum or until it blocks
– RR allocates the CPU uniformly (fairly) across participants.
– If average queue length is n, each participant gets 1/n
RR with Time Quantum = 20
Process Burst Time
P1 53
P2 17
P3 68
P4 24
• The Gantt chart is:

P1 P2 P3 P4 P1 P3 P4 P1 P3 P3

0 20 37 57 77 97 117 121 134 154 162


• Higher average turnaround than SJF,
• But better response time
Turnaround Time w/ Time Quanta
RR: Choice of Time Quantum
• Performance depends on length of the timeslice
– Context switching isn’t a free operation.
– If timeslice time is set too high
• attempting to amortize context switch cost, you get FCFS.
• i.e. processes will finish or block before their slice is up anyway

– If it’s set too low


• you’re spending all of your time context switching between threads.

– Timeslice frequently set to ~100 milliseconds


– Context switches typically cost < 1 millisecond

Moral:
Context switch is usually negligible (< 1% per timeslice)
otherwise you context switch too frequently and lose all
productivity
Scheduling Algorithms
• Multi-level Queue Scheduling
• Implement multiple ready queues based on job “type”
– interactive processes
– CPU-bound processes
– batch jobs
– system processes
– student programs
• Different queues may be scheduled using different algorithms
• Intra-queue CPU allocation is either strict or proportional
• Problem: Classifying jobs into queues is difficult
– A process may have CPU-bound phases as well as interactive ones
Multilevel Queue Scheduling
Highest priority
System Processes

Interactive Processes

Batch Processes

Student Processes
Lowest priority
Scheduling Algorithms
• Multi-level Feedback Queues
• Implement multiple ready queues
– Different queues may be scheduled using different algorithms
– Just like multilevel queue scheduling, but assignments are not static
• Jobs move from queue to queue based on feedback
– Feedback = The behavior of the job,
• e.g. does it require the full quantum for computation, or
• does it perform frequent I/O ?

• Very general algorithm


• Need to select parameters for:
– Number of queues
– Scheduling algorithm within each queue
– When to upgrade and downgrade a job
Multilevel Feedback Queues
Highest priority
Quantum = 2

Quantum = 4

Quantum = 8

FCFS

Lowest priority
A Multi-level System

I/O bound jobs


high

priority
CPU bound jobs

high
low timeslice
Multiple-Processor Scheduling
• CPU scheduling more complex when multiple CPUs are available
• Homogeneous processors within a multiprocessor
• Asymmetric multiprocessing – only one processor accesses the
system data structures, alleviating the need for data sharing
• Symmetric multiprocessing (SMP) – each processor is self-
scheduling, all processes in common ready queue, or each has
its own private queue of ready processes
• Processor affinity – process has affinity for processor on which
it is currently running
– soft affinity
– hard affinity
NUMA and CPU Scheduling
Multicore Processors

• Recent trend to place multiple processor cores on


same physical chip
• Faster and consume less power
• Multiple threads per core also growing
– Takes advantage of memory stall to make progress on
another thread while memory retrieve happens
Multithreaded Multicore System
Thread Scheduling
Since all threads share code & data segments
• Option 1: Ignore this fact
• Option 2: Gang scheduling
– run all threads belonging to a process together (multiprocessor only)
– if a thread needs to synchronize with another thread
• the other one is available and active
• Option 3: Two-level scheduling:
– Medium level scheduler
– schedule processes, and within each process, schedule threads
– reduce context switching overhead and improve cache hit ratio
• Option 4: Space-based affinity:
– assign threads to processors (multiprocessor only)
– improve cache hit ratio, but can bite under low-load condition
Real-time Scheduling
• Real-time processes have timing constraints
– Expressed as deadlines or rate requirements
• Common RT scheduling policies
– Rate monotonic
• Just one scalar priority related to the periodicity of the job
• Priority = 1/rate
• Static
– Earliest deadline first (EDF)
• Dynamic but more complex
• Priority = deadline
• Both require admission control to provide guarantees
Operating System Examples
• Solaris scheduling
• Windows XP scheduling
• Linux scheduling
Solaris Dispatch Table
Solaris Scheduling
Windows XP Priorities
Linux Scheduling
• Constant order O(1) scheduling time
• Two priority ranges: time-sharing and
real-time
• Real-time range from 0 to 99 and nice
value from 100 to 140
• (figure 5.15)
Priorities and Time-slice length
List of Tasks Indexed According to Priorities
Background
• Concurrent access to shared data may result in data
inconsistency

• Maintaining data consistency requires mechanisms to ensure


the orderly execution of cooperating processes

• Suppose that we wanted to provide a solution to the consumer-


producer problem that fills all the buffers.
– Assume an integer count keeps track of the number of full buffers.
– Initially, count is set to 0.
– It is incremented by the producer after it produces a new buffer
– It is decremented by the consumer after it consumes a buffer.
Producer-Consumer
• Producer • Consumer

while (true) { while (true) {


/* produce an item and */
while (count == 0)
/* put in nextProduced */
; // do nothing b/c empty
while (count == BUFFER_SIZE)
nextConsumed = buffer[out];
; // do nothing b/c full
out = (out + 1) % BUFFER_SIZE;
buffer [in] = nextProduced; count--;
in = (in + 1) % BUFFER_SIZE;
count++; /* consume the item */
/* in nextConsumed */
}
}
Race Condition
• count++ not atomic operation. Could be implemented as
register1 = count
register1 = register1 + 1
count = register1
• count-- not atomic operation. Could be implemented as
register2 = count
register2 = register2 - 1
count = register2

• Consider this execution interleaving with “count = 5” initially:


S0: producer execute register1 = count {register1 = 5}
S1: producer execute register1 = register1 + 1 {register1 = 6}
S2: consumer execute register2 = count {register2 = 5}
S3: consumer execute register2 = register2 - 1 {register2 = 4}
S4: producer execute count = register1 {count = 6 }
S5: consumer execute count = register2 {count = 4}
What just happened?
• Threads share global memory
• When a process contains multiple threads,
they have
– Private registers and stack memory (the context
switching mechanism needs to save and restore
registers when switching from thread to thread)
– Shared access to the remainder of the process
“state”
• This can result in race conditions
Two threads, one counter
Popular web server
• Uses multiple threads to speed things up.
• Simple shared state error:
– each thread increments a shared counter to track number of hits

hits = hits + 1;

• What happens when two threads execute concurrently?


Shared counters
• Possible result: lost update!
hits = 0
T1 T2
time
read hits (0)
read hits (0)
hits = 0 + 1
hits = 0 + 1
hits = 1
• One other possible result: everything works.
 Difficult to debug
• Called a “race condition”
Race conditions
• Def: a timing dependent error involving shared state
– Whether it happens depends on how threads scheduled
– In effect, once thread A starts doing something, it needs to “race” to
finish it because if thread B looks at the shared memory region before
A is done, it may see something inconsistent
• Hard to detect:
– All possible schedules have to be safe
• Number of possible schedule permutations is huge
• Some bad schedules? Some that will work sometimes?
– they are intermittent
• Timing dependent = small changes can hide bug

– Celebrate if bug is deterministic and repeatable!


Scheduler assumptions
Process a: Process b:
while(i < 10) while(i > -10)
i = i +1; i = i - 1;
print “A won!”; print “B won!”;

If i is shared, and initialized to 0


– Who wins?
– Is it guaranteed that someone wins?
– What if both threads run on identical speed CPU
• executing in parallel
Scheduler Assumptions
• Normally we assume that
– A scheduler always gives every executable thread
opportunities to run
• In effect, each thread makes finite progress
– But schedulers aren’t always fair
• Some threads may get more chances than others
– To reason about worst case behavior we
sometimes think of the scheduler as an adversary
trying to “mess up” the algorithm
Critical Section Goals
• Threads do some stuff but eventually might
try to access shared data

T1 T2
time
CSEnter(); CSEnter();
Critical section Critical section
CSExit(); CSExit();
T1 T2
Critical Section Goals
• Perhaps they loop (perhaps not!)

T1 T2

CSEnter(); CSEnter();
Critical section Critical section
CSExit(); CSExit();
T1 T2
Critical Section Goals
• We would like
– Safety (aka mutual exclusion)
• No more than one thread can be in a critical section at any time.
– Liveness (aka progress)
• A thread that is seeking to enter the critical section will eventually succeed
– Bounded waiting
• A bound must exist on the number of times that other threads are allowed
to enter their critical sections after a thread has made a request to enter its
critical section and before that request is granted
• Assume that each process executes at a nonzero speed
• No assumption concerning relative speed of the N processes

• Ideally we would like fairness as well


– If two threads are both trying to enter a critical section, they have equal
chances of success
– … in practice, fairness is rarely guaranteed
Solving the problem
• A first idea:
– Have a boolean flag, inside. Initially false.
Code is unsafe: thread 0 could finish the while
CSEnter() CSExit()
test when inside is false, but then 1 might call
CSEnter() before 0 can set inside to true!
{
{ inside = false;
while(inside) continue; }
inside = true;
}
• Now ask:
– Is this Safe? Live? Bounded waiting?
Solving the problem: Take 2
• A different idea (assumes just two threads):
– Have a boolean flag, inside[i]. Initially false.
Code isn’t live: with bad luck, both threads could
be looping,CSExit(int
with 0 lookingi)at 1, and 1 looking at 0
CSEnter(int i)
{
{ Inside[i] = false;
inside[i] = true; }
while(inside[i^1])
continue;
}
• Now ask:
– Is this Safe? Live? Bounded waiting?
Solving the problem: Take 3
• Another broken solution, for two threads
– Have a turn variable,Code
turn,
isn’t initially
live: thread1.
1 can’t enter unless
thread 0 did first, and vice-versa. But perhaps
CSEnter(int i) CSExit(int
one thread i) many times and the
needs to enter
{ fewer times, or not at all
other
{ turn = i ^ 1;
while(turn != i) }
continue;
}
• Now ask:
– Is this Safe? Live? Bounded waiting?
Multithreading (lets discuss this point on
IPC )
• multithreading is a specialized form of multitasking
• multitasking is the feature that allows your computer to run two
or more programs concurrently.
• In general, there are two types of multitasking: process-based
and thread-based.
• Process-based multitasking handles the concurrent execution of
programs.
• Thread-based multitasking deals with the concurrent execution
of pieces of the same program.
• A multithreaded program contains two or more parts that can
run concurrently.
• Each part of such a program is called a thread, and each thread
defines a separate path of execution
What are the differences between process
and thread?
• Threads are not independent of one other like
processes.
• as a result threads shares with other threads their:
 code section,
 data section and
 OS resources like open files and signals.
• But, like process, a thread has its own:
 program counter (PC),
 a register set, and
 a stack space.
Why Multithreading?
• Threads are popular way to improve application through parallelism.
• For example:
• browser, multiple tabs can be different threads.
• MS word uses multiple threads, one thread to format the text, other
thread to process inputs, etc.
• Threads operate faster than processes due to following reasons:
1) Thread creation is much faster.
2) Context switching between threads is much faster.
3) Threads can be terminated easily
4) Communication between threads is faster.
• C does not contain any built-in support for multithreaded applications. Instead,
it relies entirely upon the operating system to provide this feature.
How to create thread in c
• thread_create() function
• int pthread_create( pthread_t *tid, pthread_attr_t * attr_t,
void *(* start_routine) (void *), void*arg );
• threadhandle =>Thread variable (of type pthread_t)
returned by reference
• thread_attr_t *attribute =>Special Attribute for starting
thread, usually NULL
• start_routine =>Function which thread executes;
• arg =>A single argument that may be passed to
start_routine. It must be passed by reference as a pointer
cast of type void. NULL may be used if no argument is to be
passed.
Thread …
• The new POSIX thread will share some attributes with
all other threads in the same process:
– process ID (PID)
– parent process ID (PPID)
– open file descriptors
– actions taken in response to signals
– data segment (code/global variables/static
variables/constants)
– heap segment (dynamic memory)
– process environment and information (see pthreads man
page for details)
Thread …
• It will also have some distinct attributes:
– thread ID
– errno variable
– call stack (for creating distinct local variables)
– signal mask and queue
 how to differentiate thread id from process ID?
pthread_t pthread_self() => This function is like getpid()
• it returns a thread's unique thread id.
• Remember that threads are supposed to share PIDs, so
thread IDs are the way to distinguish them.
Managing Threads
• If you do not detach or join a thread, then when it exits it will
become a zombie thread and consume some system resources.
• This can really cause trouble, so make sure you take care of the
zombies before they take care of you. They will eat your
computer's brains.
• pthread_join(): to wait the main process until the joined thread
complete its task.
• pthread_exit() : when a thread complete its task make sure to
make to this call.
• pthread_cancel (): to kill a thread from another thread or
process.
What is the difference between fork() and
pthread_creat()?
• fork()
• Purpose is to create a new process, which
becomes the child process of the caller
• Both processes will execute the next instruction
following the fork() system call
• Two identical copies of the computer's address
space, code, and stack are created one for
parent and child.
• Forking causes a clone of your program
(process), that is running the code it copied.
Difference …
• pthread_create()
• Purpose is to create a new thread in the program
which is given the same process of the caller
• Threads within the same process can communicate
using shared memory. (Be careful!)
• The second thread will share data, open files, signal
handlers and signal dispositions, current working
directory, user and group ID's. The new thread will get
its own stack, thread ID, and registers though.
• Continuing the analogy: your program (process) grows
a second arm when it creates a new thread, connected
to the same brain.

You might also like