Ninghui Li Based on Slides by Prof Gustavo RodriguezRivera Topic 11 Threads and Thread Synchronization Clicker Question 1 from MidTerm Consider the following yacc code list NUMBER ID: 783740
Download The PPT/PDF document "CS252: Systems Programming" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
CS252: Systems Programming
Ninghui Li
Based on Slides by Prof. Gustavo
Rodriguez-Rivera
Topic 11:
Threads and Thread Synchronization
Slide2Clicker Question 1
from Mid-Term
Consider the following
yacc code:list : NUMBER { numbers[0] = $1; $$ = 1;} | list CM NUMBER { $$ = $1 + 1; if ($1<MAX_LENGTH) numbers[$1] = $3; }
When parsing
[2, 3, -1, 4]
When “list: NUMBER”
is used, what is value of $1?
0
1
2
3
None of the above
Slide3Clicker Question 2
from Mid-Term
Consider the following
yacc code:list : NUMBER { numbers[0] = $1; $$ = 1;} | list CM NUMBER { $$ = $1 + 1; if ($1<MAX_LENGTH) numbers[$1] = $3; }
When parsing
[2, 3, -1, 4]
How many times is
“list: list CM NUMBER”
Used?
1
2
3
4
None of the above
Slide4Clicker Question 3
from Mid-Term
Consider the following
yacc code:list : NUMBER { numbers[0] = $1; $$ = 1;} | list CM NUMBER { $$ = $1 + 1; if ($1<MAX_LENGTH) numbers[$1] = $3; }
When parsing
[2, 3, -1, 4]
At the second time
“list: list CM NUMBER”
is used, ($1,$3)=
(2,3)
(3,-1)
(3,4)
(2,4)
None of the above
Slide5Clicker Question 4
from Mid-term Exam
(
define (foo x y) (ifz x y (ifz y x (inc (foo (dec x) (dec y))))))What is the value of (foo 2 4)?0123
None of the above
Slide6Clicker Question 5
from Mid-Term
Consider the following code for the C programming question:
struct queue * new_queue() { struct queue *q = (struct queue*) malloc(sizeof(struct queue)); q->head = NULL; q->tail = NULL; return q;}void enqueue (struct queue *q, char *v) { struct node *nd = (struct node*)
malloc
(
sizeof
(struct
node));
nd
->value = v;
if (q->tail == NULL) { q->tail = nd; q->head = nd; } else { q->tail = nd; }}
How many bugs there are in
enqueue
?
0
1
2
3
4 or more
Slide7Introduction to Threads
A thread is a path execution
By default, a C/C++ program has one thread called "main thread" that starts the main() function.
main() --- --- printf( "hello\n" ); ---}
Slide8Introduction to Threads
You can create multiple paths of execution using:
POSIX threads ( standard )
pthread_create( &thr_id, attr, func, arg )WindowsCreateThread(attr, stack_size, func, arg, flags, &thr_id)
Slide9Introduction to Threads
Every thread will have its own
Stack
PC – Program counterSet of registersStateThis information is stored in entry corresponding to the process in the process table entryEach thread will have its own function calls, and local variables.
Slide10Memory Layout of Threads
A single-threaded process
A process with two threads
Slide11Applications of Threads
Concurrent Server applications
Assume a web server that receives two requests:
First, one request from a computer connected through a modem that will take 2 minutes. Then another request from a computer connected to a fast network that will take .01 secs. If the web server is single threaded, the second request will be processed only after 2 minutes.In a multi-threaded server, two threads will be created to process both requests simultaneously. The second request will be processed as soon as it arrives.
Slide12Application of Threads
Taking Advantage of Multiple CPUs
A program with only one thread can use only one CPU. If the computer has multiple cores, only one of them will be used.
If a program divides the work among multiple threads, the OS will schedule a different thread in each CPU.This will make the program run faster.
Slide13Applications of Threads
Interactive Applications.
Threads simplify the implementation of interactive applications that require multiple simultaneous activities.
Assume an Internet telephone application with the following threads:Player thread - receives packets from the internet and plays them.Capture Thread – captures sound and sends the voice packetsRinger Server – Receives incoming requests and tells other phones when the phone is busy.Having a single thread doing all this makes the code cumbersome and difficult to read.
Slide14Advantages and Disadvantages of Threads vs. Processes
Advantages of Threads
Fast thread creation
- creating a new path of execution is faster than creating a new process with a new virtual memory address space and open file table.Fast context switch - context switching across threads is faster than across processes.Fast communication across threads – threads communicate using global variables that is faster and easier than processes communicating through pipes or files.
Slide15Advantages and Disadvantages of Threads vs. Processes
Disadvantages of Threads
Threads are less robust than processes
– If one thread crashes due to a bug in the code, the entire application will go down. If an application is implemented with multiple processes, if one process goes down, the other ones remain running.Threads have more synchronization problems – Since threads modify the same global variables at the same time, they may corrupt the data structures. Synchronization through mutex locks and semaphores is needed for that. Processes do not have that problem because each of them have their own copy of the variables.
Slide16Synchronization Problems with Multiple Threads
Threads share same global variables.
Multiple threads can modify the same data structures at the same time
This can corrupt the data structures of the program.Even the most simple operations, like increasing a counter, may have problems when running multiple threads.
Slide17Example of Problems with Synchronization
// Global counter
int
counter = 0;void increment_loop(void *arg){ int i; int max = * ((int *)arg); for(i=0;i<max;i++){ int
tmp
= counter;
tmp
=tmp+1;
counter=
tmp
;
}
}
Slide18Example of Problems with Synchronization
int
main(){
pthread_t t1,t2; int max = 10000000; void *ret; pthread_create(&t1,NULL, increment_loop,(void*)&max); pthread_create(&t2,NULL, increment_loop,(void*)&max);
//wait until threads finish
pthread_join
(t1, &ret);
pthread_join
(t2, &ret);
printf
(“counter total=%
d”,counter);}
Slide19Example of Problems with Synchronization
We would expect that the final value of counter would be
10,000,000+ 10,000,000= 20,000,000
but very likely the final value will be less than that (E.g. 12804354).The context switch from one thread to another may change the sequence of events so the counter may loose some of the counts.
Slide20Example of Problems with Synchronization
int counter = 0;
void increment_loop(int max){
for(int i=0;i<max;i++){ a)int tmp= counter; b)tmp=tmp+1; c)counter=tmp; }}T2int counter = 0;void increment_loop(int max){
for(int i=0;i<max;i++){
a)int tmp = counter;
b)tmp=tmp+1;
c)counter=tmp;
}
}
T1
Slide21Example of Problems with Synchronization
T1
T2
T0 (main)for(…)a)tmp1=counter (tmp1=0)(Context switch)
Join t1
(wait)
Starts running
a)tmp2=counter
(tmp2=0)
b)tmp2=tmp2+1
c)counter=tmp2
Counter=1
a)b)c)a)b)c)…
Counter=23
(context switch)
b)tmp1=tmp1+1
c)counter=tmp1
Counter=1
time
Slide22Example of Problems with Synchronization
As a result 23 of the increments will be lost.
T1 will reset the counter variable to 1 after T2 increased it 23 times.
Even if we use counter++ instead of a)b) c) we still have the same problem because the compiler will generate separate instructions that will look like a)b)c).Worse things will happen to lists, hash tables and other data structures in a multi-threaded program.The solution is to make certain pieces of the code Atomic.
Slide23Atomicity
Atomic Section:
A portion of the code
that needs to appear to the rest of the system to occur instantaneously.Otherwise corruption of the variables is possible. An atomic section is also called sometimes a “Critical Section”
Slide24Atomicity by disabling interrupts
On
uni
-processor, operation is atomic as long as context switch doesn’t occur during operationTo achieve atomicity: disable interrupts upon entering atomic section, and enable upon leavingContext switches cannot happen with interrupt disabled.Available only in kernel mode; thus only used in kernel programmingOther interrupts may be lost.Does not provide atomicity with multiprocessor
Slide25Achieving Atomicity in Concurrent Programs
Our main goal is to learn how to write concurrent programs using synchronization tools
We also explain a little bit how these tools are implemented
Concurrent ProgramHigh-level synchronization tools (mutex locks, semaphores, condition variables, read/write locks)Hardware support (interrupt disable/enable, test & set, and so on)
Slide26Atomicity by Mutex Locks
Mutex
Locks
are software mechanisms that enforce atomicityOnly one thread can hold a mutex lock at a timeWhen a thread tries to obtain a mutex lock that is held by another thread, it is put on hold (aka put to sleep, put to wait, blocked, etc).The thread may be waken up when the lock is available to the thread.Think of it as a locker in a gym with a lock and a key on it.
Slide27Mutex Locks Usage
Declaration
:
#include <pthread.h>pthread_mutex_t mutex;Initializepthread_mutex_init( &mutex, atttributes);Start atomic sectionpthread_mutex_lock(&mutex);End atomic sectionpthread_mutex_unlock(&mutex);
Slide28Example of Mutex Locks
#include <
pthread.h
>int counter = 0; // Global counterpthread_mutex_t mutex;void increment_loop(int max){ for(int i=0;i<max;i++){ pthread_mutex_lock(&mutex); int tmp = counter;
tmp
=tmp+1;
counter=
tmp
;
pthread_mutex_unlock
(&
mutex
); }}Threads
Slide29Example of Mutex Locks
int main(){
pthread_t t1,t2;
pthread_mutex_init(&mutex,NULL); pthread_create(&t1,NULL, increment,10000000); pthread_create(&t2,NULL, increment,10000000); //wait until threads finish pthread_join(&t1); pthread_join(&t2); printf(“counter total=%d”,counter);}
Slide30Example of Mutex Locks
T1
T2T0 (main)for(…)mutex_lock(&m) a)tmp1=counter (tmp1=0)
(Context switch)
Join t1
(wait)
Starts running
mutex_lock(&m)
(wait)
(context switch)
b)tmp1=tmp1+1
c)counter=tmp1
Counter=1
mutex_unlock(&m)
a)tmp2=counter
b)tmp2=tmp2+1
c)counter=tmp2
time
Slide31Example of Mutex Locks
As a result, the steps a),b),c) will be atomic so the final counter total will be
10,000,000+ 10,000,000= 20,000,000
no matter if there are context switches in the middle of a)b)c)
Slide32Mutual Exclusion
Mutex
Locks
enforce the mutual exclusion of all code between lock and unlockMutex_lock(&m)ABCMutex_unlock(&m)Mutex_lock(&m)DEFMutex_unlock(&m)
Slide33Mutual Exclusion
This means that the sequence ABC, DEF, can be executed as an atomic block without interleaving.
Time ------------------------>
T1 -> ABC ABCT2 -> DEF DEFT3 -> ABC DEF
Slide34Mutual Exclusion
If different
mutex
locks are used (m1!=m2) then the sections are no longer atomicABC and DEF can interleaveMutex_lock(&m1)ABCMutex_unlock(&m1)Mutex_lock(&m2)DEFMutex_unlock(&m2)
Slide35Test_and_set
There is an instruction
test_and_set
that atomically set a variable to a certain value, and return its original valuePseudocode: int test_and_set(int *v){ int oldval = *v; *v = 1; return oldval; }This instruction is implemented by the CPU. You don’t need to implement it.
Slide36Implementing Mutex Locks using Test and Set (pseudo code)
mutex_lock
(
mutex) { while (test_and_set (&mutex.m) != 0); if (mutex.lock) { mutex.queue( currentThread)); mutex.m = 0;
setWaitState
();
pthread_yield
();
} else{
mutex.lock
= true; mutex.m = 0; }}The
mutex
has the following fields:
lock
indicates whether the
mutex
has been locked by some thread
queue
stores all threads that are waiting for the
mutex
m
ensures that only one thread is performing update to lock & queue
Implements a busy-wait lock (aka spin lock).
Slide37Implementing Mutex Locks using Test and Set (pseudo code)
mutex_unlock
() {
while (test_and_set (&mutex.m) != 0); if (mutex.queue. nonEmpty) { t=mutex.dequeue(); t.setReadyState(); } else { mutex.lock=false; }
mutex.m
= 0;
}
If some thread is waiting, get the first thread ready to run, keep the
mutex
locked, because now this thread holds the
mutex
.
Implements a busy-wait lock (aka spin lock).
Slide38Review Questions
What does the system need to maintain for each thread?
Why one wants to use multiple threads?
What are the pros and cons of using threads vs. processes?What is an atomic section? Why disabling interrupt ensures atomicity on a single CPU machine?
Slide39Review Questions
What is the meaning of the “test and set” primitive?
What is a
mutex lock? What is the semantics of lock and unlock calls on a mutex lock?How to use mutex locks to achieve atomicity?The exam does not require implementation of mutex lock.