• No results found

Grundlagen der Betriebssystemprogrammierung

N/A
N/A
Protected

Academic year: 2021

Share "Grundlagen der Betriebssystemprogrammierung"

Copied!
73
0
0

Loading.... (view fulltext now)

Full text

(1)

Pr¨asentation A3, A4, A5, A6

GLBS Tutoren

21. M¨arz 2013

IAIK

(2)

1 A3 - Function Pointers

2 A4 - C++: The good, the bad and the ugly

3 A5 - Multithreading

4 A6 - Shell

(3)

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

(4)

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.

(5)

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)

(6)

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.

(7)

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.

(8)

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.

(9)

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.

(10)

First Steps Pull upstream Read the wiki page.

Learn about function pointers.

Implement all lines marked with TODO.

(11)

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

(12)

Revisiting C++

Outline

References and Pointers Templates

Operator overloading STL and Containers RAII

A4 - Revisiting C++

(13)

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

(14)

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

(15)

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

(16)

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

(17)

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!

(18)

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!

(19)

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

(20)

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)

(21)

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)

(22)

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 . . .

(23)

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 . . .

(24)

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 ; };

(25)

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 ) ;

(26)

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

(27)

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

(28)

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!

(29)

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!

(30)

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!

(31)

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

(32)

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

(33)

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

(34)

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?

(35)

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!”.

(36)

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!”.

(37)

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!

(38)

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?

(39)

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

(40)

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

(41)

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 " ; }

}

(42)

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 ) ;

(43)

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)!

(44)

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.

(45)

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.

(46)

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.

(47)

# 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).

(48)

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 }

(49)

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

(50)

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

(51)

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

(52)

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 :)

(53)

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 :)

(54)

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 :)

(55)

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.

(56)

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.

(57)

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, ..

(58)

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, ..

(59)

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.

(60)

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.

(61)

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.

(62)

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

(63)

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

(64)

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 ) ;

(65)

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) ;

(66)

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!

(67)

File Descriptors

A file descriptor has type int You know FILE*?

FILE struct contains file descriptor (abstraction) fopen → open

fread → read etc.

(68)

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 )

(69)

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 ! " ) ;

(70)

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

(71)

# 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 ) ;

(72)

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.

(73)

References

Related documents

Typological congruence between Gurindji coverbs and Kriol main verbs had a number of results which directly affected the formation of the Gurindji Kriol asymmetrical serial

The shared clause declares the variables in the list to be shared among all the threads in a team. All threads within a team access the same storage area for

• Priority Donation - If a thread attempts to acquire a resource (lock) that is currently being held, it donates its effective priority to the holder of that resource?. This must

Vertinant nekilnojamojo turto mokesèiø ir teisinës valstybës principo atitikimà, turi bûti ávertinta, ar asmenys gali pagrástai tikëtis, kad ðis turtas bus neapmokestinamas ir

This requires careful programming because threads share data structures that are modified by another thread at a time and also because threads shares the same address space.. The

REVISED Due Dates, 2020 TTI 1 Strategic plan basics 1 st Draft of Plan due To SPA team March 2-5 Webinar Needs assessment March 24 May 15 UNH.SPA.Team@unh.edu 2020 SP

03.01.01 Safety Program: The aviation unit Safety Program shall be a written policy incorporated in the unit’s Operations Manual or in a separate manual, and shall include, but

This research uses a single case study, the Bentley School District (pseudonym), to examine the implementation, impact and results the district has had using the FFT as an