Pr¨asentation A3, A4, A5, A6
GLBS Tutoren
21. M¨arz 2013
IAIK
1 A3 - Function Pointers
2 A4 - C++: The good, the bad and the ugly
3 A5 - Multithreading
4 A6 - Shell
A1, A2, A3 Git, Compiler, C, C++
A4, A5, A6 Multithreading, more C, more C++
A7, A8, A9
Synchronization, Thread and Process Interaction A10, A11, A12
OS Topics
About Function Pointers
Facts
Pointer store the address of an object in memory.
Integer pointers store the address of an integer.
Function pointers store the address of a function.
A function call includes a jump to an address (and back).
This address is stored in a function pointer variable.
Declaration
int (* m y _ m a i n ) ( int , c h a r **) = & m a i n ; int (* m y _ m a i n ) ( int , c h a r **) = m a i n ;
v o i d *(* s t a r t _ r o u t i n e ) ( v o i d *) = m y _ t h r e a d ; The address-of operator & is optional.
The parenthesis are important!
The type must be correct!
(Argument type & number, return type)
Function Pointer Syntax
Usage
int r e t u r n v a l u e = m a i n ( argc , a r g v ) ; v o i d * r e t u r n d a t a = s t a r t _ r o u t i n e ( i n p u t ) ; Like a statically defined function.
Task Overview
Given: a source file with a static array and bubble sort implementation.
main calls qsort (form C-library) and bsort to sort static array.
v o i d q s o r t ( v o i d * base , s i z e _ t num , s i z e _ t size , int (* c o m p a r ) ( c o n s t v o i d * , c o n s t v o i d *) ) ;
sortAndPrintArray takes sort-function and compare-function to sort array.
Define (typedef) two function pointer types for the sort and the compare function.
Complete the bsort function.
Call the appropriate sort function in sortAndPrintArray.
A3 - Function Pointers
Task Overview
Given: a source file with a static array and bubble sort implementation.
main calls qsort (form C-library) and bsort to sort static array.
v o i d q s o r t ( v o i d * base , s i z e _ t num , s i z e _ t size , int (* c o m p a r ) ( c o n s t v o i d * , c o n s t v o i d *) ) ;
sortAndPrintArray takes sort-function and compare-function to sort array.
Define (typedef) two function pointer types for the sort and the compare function.
Complete the bsort function.
Call the appropriate sort function in sortAndPrintArray.
Task Overview
Given: a source file with a static array and bubble sort implementation.
main calls qsort (form C-library) and bsort to sort static array.
v o i d q s o r t ( v o i d * base , s i z e _ t num , s i z e _ t size , int (* c o m p a r ) ( c o n s t v o i d * , c o n s t v o i d *) ) ;
sortAndPrintArray takes sort-function and compare-function to sort array.
Define (typedef) two function pointer types for the sort and the compare function.
Complete the bsort function.
Call the appropriate sort function in sortAndPrintArray.
First Steps Pull upstream Read the wiki page.
Learn about function pointers.
Implement all lines marked with TODO.
Some thoughts about C++
In C++ it’s harder to shoot yourself in the foot, but when you do, you blow off your whole leg. - Bjarne Stroustrup
Revisiting C++
Outline
References and Pointers Templates
Operator overloading STL and Containers RAII
A4 - Revisiting C++
What is a pointer?
We know that already!
int n = 41;
int * ptr = & n ;
* ptr ++; // now n is 42
But what is a reference?
Simplified: behaves like a pointer, but is syntactically used like a simple copy.
int n = 42;
int & ptr = n ;
ptr ++; // now n is 42
References and Pointers
What is a pointer?
We know that already!
int n = 41;
int * ptr = & n ;
* ptr ++; // now n is 42
But what is a reference?
Simplified: behaves like a pointer, but is syntactically used like a simple copy.
int n = 42;
int & ptr = n ;
ptr ++; // now n is 42
What is a reference?
more precisely: an alias for an object In contrast to pointers...
no pointer-arithmetic
each reference has to be initalised with a valid object no null-pointer for references
References and Pointers
What is a reference?
more precisely: an alias for an object In contrast to pointers...
no pointer-arithmetic
each reference has to be initalised with a valid object no null-pointer for references
Call by reference
Changing an object by a function / method
b o o l l o a d P l a y e r s ( std :: vector < P l a y e r * >& vec ) ; performance reasons:
just pass a reference instead of copying the whole object.
v o i d d i s p l a y P l a y e r s (
c o n s t std :: vector < P l a y e r * >& vec ) c o n s t ; const is important!
References and Pointers
Call by reference
Changing an object by a function / method
b o o l l o a d P l a y e r s ( std :: vector < P l a y e r * >& vec ) ; performance reasons:
just pass a reference instead of copying the whole object.
v o i d d i s p l a y P l a y e r s (
c o n s t std :: vector < P l a y e r * >& vec ) c o n s t ; const is important!
Implicit conversion
int n = 1 0 2 4 ;
l o n g m = n ; // i m p l i c i t t y p e c a s t
Explicit conversion dynamic cast static cast reinterpret cast
C-style cast
Type Casting
dynamic cast
c l a s s B a s e { v i r t u a l v o i d do () {} };
c l a s s D e r i v e d : p u b l i c B a s e { };
B a s e * b a s e = new D e r i v e d () ;
D e r i v e d * d = d y n a m i c _ c a s t < D e r i v e d * >( b a s e ) ; works only with pointers and references to objects requires Run-time type information (RTTI) ...
... and a polymorphic object as operand used for downcasts (see example) runtime overhead (safe but slow)
static cast
checks done at compile time → no runtime checks!
be careful with casts between pointers to related classes!
static cast performs conversions between...
pointers to related classes.
enums and integral types.
floating point values and integral types.
used for downcasts (see example)
Type Casting
reinterpret cast
converts any pointer to any pointer type reinterprets the given bits in a new way no checks done → always possible
results are system-specific and therefor not portable remember what Bjarne Stroustrup said!
however sometimes it is necessary
Low level code
headers in a binary file data structures in file systems . . .
reinterpret cast
converts any pointer to any pointer type reinterprets the given bits in a new way no checks done → always possible
results are system-specific and therefor not portable remember what Bjarne Stroustrup said!
however sometimes it is necessary
Low level code
headers in a binary file data structures in file systems . . .
Type Casting
reinterpret cast low-level example
s t r u c t m i n i x _ s u p e r _ b l o c k {
u i n t 1 6 s _ n i n o d e s ; u i n t 1 6 s _ n z o n e s ; u i n t 1 6 s _ i m a p _ b l o c k s ; u i n t 1 6 s _ z m a p _ b l o c k s ; u i n t 1 6 s _ f i r s t d a t a z o n e ; u i n t 1 6 s _ l o g _ z o n e _ s i z e ; u i n t 3 2 s _ m a x _ s i z e ; u i n t 1 6 s _ m a g i c ; u i n t 1 6 s _ s t a t e ; u i n t 3 2 s _ z o n e s ; };
reinterpret cast low-level example
c h a r b u f f e r [ M I N I X _ B L O C K _ S I Z E ];
if (! device - > r e a d S e c t o r ( sector , buffer , M I N I X _ B L O C K _ S I Z E ) ) {
r e t u r n f a l s e ; }
m i n i x _ s u p e r _ b l o c k s u p e r b l o c k =
* r e i n t e r p r e t _ c a s t < m i n i x _ s u p e r _ b l o c k * >( b u f f e r + o f f s e t ) ;
Templates
What are templates? (Theory) Take a class/function definition
Generalize it by allowing parameterization
→ You have a template (class/function)
What are templates? (Practice)
”Parameterization” only works on types (and integral constants)
Luckily, you can model (almost) anything using types
What are templates? (Theory) Take a class/function definition
Generalize it by allowing parameterization
→ You have a template (class/function)
What are templates? (Practice)
”Parameterization” only works on types (and integral constants)
Luckily, you can model (almost) anything using types
Templates, example
We have:
s h o r t max ( s h o r t a , s h o r t b ) {
r e t u r n ( a > b ) ? a : b ; }
That seems useful! Let’s template it:
t e m p l a t e < t y p e n a m e T >
T m a x 1 ( T a , T b ) {
r e t u r n ( a > b ) ? a : b ; }
That was easy! Templates are fun!
We have:
s h o r t max ( s h o r t a , s h o r t b ) {
r e t u r n ( a > b ) ? a : b ; }
That seems useful! Let’s template it:
t e m p l a t e < t y p e n a m e T >
T m a x 1 ( T a , T b ) {
r e t u r n ( a > b ) ? a : b ; }
That was easy! Templates are fun!
Templates, template parameters
Consider again
t e m p l a t e < t y p e n a m e T >
T m a x 1 ( T a , T b ) {
r e t u r n ( a > b ) ? a : b ; }
What assumptions do we make about ”T”?
Each ”T” must be ”greater than”-comparable.
Compiler will reject any type that does not fulfill this Requirements on template parameters are important documentation!
Back to our example. One problem:
s h o r t a = 3;
s h o r t b = max ( a , 5) ; // t h i s w o r k s s h o r t c = m a x 1 ( a , 5) ; // t h i s d o e s not
prog.cpp:11: error: no matching function for call to max1(short int&, int)
Template parameters must match exactly, no conversion is done by the compiler.Workarounds:
s h o r t d = max1 < short >( a , 5) ; // F o r c e s p e c i f i c i n s t a n t i a t i o n
s h o r t e = m a x 1 ( a , ( s h o r t ) 5) ; // C a s t i n t e g e r l i t e r a l to s h o r t
Templates, pitfalls
Back to our example. One problem:
s h o r t a = 3;
s h o r t b = max ( a , 5) ; // t h i s w o r k s s h o r t c = m a x 1 ( a , 5) ; // t h i s d o e s not
prog.cpp:11: error: no matching function for call to max1(short int&, int)
Template parameters must match exactly, no conversion is done by the compiler. Workarounds:
s h o r t d = max1 < short >( a , 5) ; // F o r c e s p e c i f i c i n s t a n t i a t i o n
s h o r t e = m a x 1 ( a , ( s h o r t ) 5) ; // C a s t i n t e g e r l i t e r a l to s h o r t
What about classes?
t e m p l a t e < t y p e n a m e T > c l a s s A {
p u b l i c :
t y p e d e f std :: vector < T > T V e c ; };
t e m p l a t e < t y p e n a m e T > c l a s s B : p u b l i c A < T >
{
p u b l i c :
v o i d f i l l ( c o n s t T V e c & e l e m e n t s ) ; };
prog.cpp:11: error: expected ’,’ or ’...’ before ’&’ token prog.cpp:11: error: ISO C++ forbids declaration of
’TVec’ with no type
Templates, ugly pitfalls
Let’s try:
v o i d f i l l ( c o n s t A < T >:: T V e c & e l e m e n t s ) ;
prog.cpp:11: error: expected unqualified-id before ’&’ token
prog.cpp:11: error: expected ’,’ or ’...’
before ’&’ token
Not much better. What does the compiler think this is, if not a type?
A<T>::TVecmay not name a type for every ”T” → template specialization.
Consider:
template<int> class A {
public:
static int TVec;
};
If we instantiateB<int>,A<T>::TVec is not a type!
Workaround:
v o i d f i l l ( c o n s t t y p e n a m e A < T >:: T V e c & e l e m e n t s ) ; Assure the compiler ”This is a typename!”.
Templates, ”typename”
A<T>::TVecmay not name a type for every ”T” → template specialization.
Consider:
template<int> class A {
public:
static int TVec;
};
If we instantiateB<int>,A<T>::TVec is not a type!
Workaround:
v o i d f i l l ( c o n s t t y p e n a m e A < T >:: T V e c & e l e m e n t s ) ; Assure the compiler ”This is a typename!”.
All types used formax1 have to be ”greater than”-comparable.
What if we want to use our own class? Operator overloading!
c l a s s S o r t a b l e { p u b l i c :
b o o l o p e r a t o r >( c o n s t S o r t a b l e & o t h e r ) ; };
Also useful to provide an intuitive interface to your class (e.g. for (mathematical) vectors, matrices, ...).
Note: Don’t overdo it!
Standard containers
The C++ standard library provides some container class templates:
vector<T>
list<T>
map<K,T>
set<K>
...
Important: Which requirements do ”T” and ”K” have to fulfill?
Value types have to fulfill the following:
Be copy-constructible
Implements assigment operator
Some operations also require: Be default-constructible Key types have to fulfill the following:
Be copy-constructible
Implements assigment operator Be ”less than”-comparable
(Ordering has to be a strict weak ordering)
Some operations also require: Be default-constructible
Container requirements
Value types have to fulfill the following:
Be copy-constructible
Implements assigment operator
Some operations also require: Be default-constructible Key types have to fulfill the following:
Be copy-constructible
Implements assigment operator Be ”less than”-comparable
(Ordering has to be a strict weak ordering)
Some operations also require: Be default-constructible
Containers define iterator types. These ”behave” like pointers into the container
v o i d m y f u n c ( std :: vector < int > vec ) {
for ( std :: vector < int >:: i t e r a t o r it = vec . b e g i n () ; it != vec . end () ; ++ it )
{
std :: c o u t < < (* it ) < < " \ n " ; }
}
Iterators, why?
Consider the following task: Provide a function to print an arbitrary number of integer values in a consistent format.
What’s better?
v o i d p r i n t V a l u e s P t r ( int * ptr , int n ) ;
v o i d p r i n t V a l u e s V e c ( std :: vector < int > v a l u e s ) ;
Answer: Neither! Use templates!
t e m p l a t e < t y p e n a m e I n p u t I t e r a t o r >
v o i d p r i n t V a l u e s T e m p l a t e ( I n p u t I t e r a t o r it , int n )
{
for ( int i = 0; i < n ; ++ i , ++ it )
std :: c o u t < < " v a l u e : " < < (* it ) < < " \ n " ; }
Pointers and iterators support the same interface (increment and dereferencing)!
std::map
std::map<K,T>is an associative container mapping arbitrary (comparable) ”K”s to ”T”s.
std :: map < std :: string , int > m y m a p ; int x = m y m a p [ " k e y 1 " ];
What will happen?
Answer:operator[] always returns a reference.
If the entry does not exist, it will be created!
if ( m y m a p . f i n d ( " k e y 1 " ) != m y m a p . end () ) x = m y m a p [ " k e y 1 " ];
map<K,T>::find(const K&)returns an iterator
it will point one past the end (equal tomap<K,T>::end()) in case the key is not found.
std::map<K,T>is an associative container mapping arbitrary (comparable) ”K”s to ”T”s.
std :: map < std :: string , int > m y m a p ; int x = m y m a p [ " k e y 1 " ];
What will happen?
Answer:operator[] always returns a reference.
If the entry does not exist, it will be created!
if ( m y m a p . f i n d ( " k e y 1 " ) != m y m a p . end () ) x = m y m a p [ " k e y 1 " ];
map<K,T>::find(const K&)returns an iterator
it will point one past the end (equal tomap<K,T>::end()) in case the key is not found.
RAII, basics
”Resource Acquisition Is Initialization” - Acquiring and securely releasing resources.
Bit of a misnomer: No one cares about acquisition, releasing resources is more important.
Basic idea: Constructor acquires resource (file handle, memory, network connection, ...), destructor frees it again.
When the object is allocated on the stack (i.e. as a local variable), the destructor will be called automatically when the enclosing scope is left.
# i n c l u d e < memory >
int m a i n () {
std :: a u t o _ p t r < int > m y p t r ( new int ) ;
r e t u r n 0; // M e m o r y is f r e e d a u t o m a t i c a l l y ! }
Too badauto_ptris pretty useless (not copy-able).
Better memory management using Shared Pointer
Idea: Let’s count how many references exist for a resource. When this count reaches zero, the resource can be freed.
b o o s t :: s h a r e d _ p t r < int > m y f u n c () {
b o o s t :: s h a r e d _ p t r < int > r e s u l t ( new int ) ; r e t u r n r e s u l t ; // w o u l d not w o r k w i t h
a u t o _ p t r }
int m a i n () {
b o o s t :: s h a r e d _ p t r < int > m y p t r = m y f u n c () ; r e t u r n 0; // again , m e m o r y is f r e e d
a u t o m a t i c a l l y }
shared_ptr maintains a reference counter
Assignment operator and copy constructor make reference counter shared between differentshared_ptrs to the same object
Problem: Circular dependencies (reference count will always stay ≥ 1)
Other ”problem”: Only available in boost and C++11, but basic functionality is easy to implement
Placement new
operator newdoes two things:
Allocate memory
Call constructor on allocated memory What if we only want to do the second?
Placementnew:
new ( ptr ) M y C l a s s () ;
Call constructor for MyClasson memory pointed to by ptr Potential uses: Memory pools, memory mapped hardware, shared memory
But: There is almost always an alternative
operator newdoes two things:
Allocate memory
Call constructor on allocated memory What if we only want to do the second?
Placementnew:
new ( ptr ) M y C l a s s () ;
Call constructor for MyClasson memory pointed to by ptr Potential uses: Memory pools, memory mapped hardware, shared memory
But: There is almost always an alternative
A4 - Revisiting C++
Task Overview
Given: some C++ files.
everything compiles fine but does not run... :(
fix the code so that the program prodces the provided reference output.
DO NOT change existing method signatures or members!
You must NOT create any additional output!
Just fix the bugs :)
Task Overview
Given: some C++ files.
everything compiles fine but does not run... :(
fix the code so that the program prodces the provided reference output.
DO NOT change existing method signatures or members!
You must NOT create any additional output!
Just fix the bugs :)
A4 - Revisiting C++
Task Overview
Given: some C++ files.
everything compiles fine but does not run... :(
fix the code so that the program prodces the provided reference output.
DO NOT change existing method signatures or members!
You must NOT create any additional output!
Just fix the bugs :)
Pull upstream Read the wiki page.
Search all bugs and fix them.
Rember the pitfalls we just discussed.
Some of them are hidden in the code.
Threads and Processes
The operating system ..
can run multiple programs “simultaneously“.
switches between running progams and shares the CPU → Timesharing.
decides when it switches.
saves and restores the process context.
provides a ’virtual’ CPU for every process, i.e. they don’t notice that they share the CPU.
A process ..
is an instance of an executing program.
has it’s own virtual address space, separating it from other processes and the OS.
has it’s set of state variables (e.g. file descriptors)
A thread ..
is a sequential thread of execution in a program.
belongs to a process (a userthread).
is scheduled by the OS, i.e. granted CPU time.
has it’s own context: program counter, cpu registers, ..
Threads and Processes
A process ..
is an instance of an executing program.
has it’s own virtual address space, separating it from other processes and the OS.
has it’s set of state variables (e.g. file descriptors)
A thread ..
is a sequential thread of execution in a program.
belongs to a process (a userthread).
is scheduled by the OS, i.e. granted CPU time.
has it’s own context: program counter, cpu registers, ..
When a program is started ..
the OS creates a new process.
the new process gets one new thread that starts at the program entry point.
Multiple threads ..
can be created within a process by using a library (that finally tells the OS). → POSIX threads, pthreads.
Every thread has it’s own execution context.
But within a process, all threads share the same address space and other process resources like file descriptors and others.
Threads and Processes
When a program is started ..
the OS creates a new process.
the new process gets one new thread that starts at the program entry point.
Multiple threads ..
can be created within a process by using a library (that finally tells the OS). → POSIX threads, pthreads.
Every thread has it’s own execution context.
But within a process, all threads share the same address space and other process resources like file descriptors and others.
Task Overview
Given: a almost complete textmode game.
An example for using multiple threads in a simple application.
Thread 1 displays the gfx.
Thread 2 waits for keyboard input.
To do
Pull upstream.
Read the wiki.
Run the second thread Play the game.
Submit.
A6 - Shell
Task Overview Minimal Shell TODOs in the code:
1 Process creation
2 Pipe commands |, <, >, etc.
First Steps Pull upstream
Try make and execute the shell
Process Creation
Windows way: CreateProcess Unix way: fork, exec
Fork
Creates a new process. Shall be an exact copy ...
Exec
Replaces current process image (Tries to) execute the given binary file
A6 - Shell
Fork Example
# i n c l u d e < u n i s t d . h >
// p i d _ t f o r k ( v o i d ) ; int pid = f o r k () ; if ( pid == 0)
p r i n t f ( " I ’ m the c h i l d \ n " ) ; e l s e
p r i n t f ( " I ’ m the parent , "
" and my c h i l d has pid % u \ n " , pid ) ;
Exec Example
# i n c l u d e < u n i s t d . h >
c h a r * c o n s t i n p u t _ a r g v [] = { " f i l e . txt " , 0};
// int e x e c v ( c o n s t c h a r * path , // c h a r * c o n s t a r g v []) ; e x e c v ( " / bin / vim " , i n p u t _ a r g v ) ; p r i n t f ( " If p r o g r a m f l o w g e t s h e r e "
" s o m e t h i n g w e n t t e r r i b l y w r o n g !\ n " ) ; e x i t ( -1) ;
A6 - Shell
Process Creation
fork followed by an exec?
Worse than the CreateProcess approach?
No, because of cow:
Forked process shares memory with the old process Memory is copied upon write access
→ Almost nothing copied if followed by an exec!
But how do i get output of the new process?
→ Pipes!
File Descriptors
A file descriptor has type int You know FILE*?
FILE struct contains file descriptor (abstraction) fopen → open
fread → read etc.
A6 - Shell
Pipes
a pair of 2 special file descriptors
“read end” and “write end”
# i n c l u d e < u n i s t d . h >
int p i p e f d [ 2 ] ;
// int p i p e ( int p i p e f d [ 2 ] ) ; p i p e ( p i p e f d ) ;
w r i t e ( p i p e f d [1] , " h e l l o w o r l d \ n " , 12) ; // m i g h t b l o c k
c h a r t e x t [ 1 3 ] ;
r e a d ( p i p e f d [0] , text , 12) ; // w i l l b l o c k ( if no i n p u t a v a i l a b l e )
How to use pipes instead of STDOUT FILENO, etc.?
fork/exec leave file descriptors as they are!
But how to change STDOUT FILENO to a pipe write end?
dup2!
int fd = o p e n ( " o u t p u t . txt " , O _ R D W R | O _ C R E A T | O _ T R U N C ) ;
d u p 2 ( fd , S T D O U T _ F I L E N O ) ;
p r i n t f ( " t h i s w i l l be w r i t t e n to o u t p u t . txt , but NOT to the t e r m i n a l ! " ) ;
A6 - Shell
How to wait until a process terminated?
# i n c l u d e < sys / t y p e s . h >
# i n c l u d e < sys / w a i t . h >
int pid = f o r k () ; if ( pid == 0) {
// do s o m e t h i n g e x i t (0) ;
}
// p i d _ t w a i t p i d ( p i d _ t pid , int * status ,
// int o p t i o n s ) ;
w a i t p i d ( pid , 0 , 0) ; // l o o k at the man p a g e
# d e f i n e R E A D _ S T D O U T _ F I L E N O p i p e [0]
# d e f i n e W R I T E _ S T D O U T _ F I L E N O p i p e [1]
int p i p e [ 2 ] ; p i p e ( p i p e ) ;
int pid = f o r k () ; if ( pid == 0) {
d u p 2 ( W R I T E _ S T D O U T _ F I L E N O , S T D O U T _ F I L E N O ) ; c l o s e ( R E A D _ S T D O U T _ F I L E N O ) ; // why ?
e x e c v ( path_ , ( c h a r * c o n s t *) a r g s _ ) ; }
w a i t p i d ( child , 0 , 0) ;
c l o s e ( W R I T E _ S T D O U T _ F I L E N O ) ; // why ?
r e a d ( R E A D _ S T D O U T _ F I L E N O , buf , B U F F E R _ S I Z E ) ; c l o s e ( R E A D _ S T D O U T _ F I L E N O ) ;
A6 - Shell
Pipes in the shell
./prog1 < file.txt
1 Open file.txt
2 Read from file, write into pipe
3 Replace STDIN FILENO of forked process by this pipe (dup2) ./prog1 > file.txt
1 Open file.txt
2 Replace STDOUT FILENO of forked process by a pipe
3 Read from pipe, write into file ls | less
1 Run ls with STDOUT FILENO replaced by pipe[1]
2 Run less with STDIN FILENO replaced by pipe[0]
etc.