operating systems, 112 practical session 3 threads 1

41
Operating Systems, 112 Practical Session 3 Threads 1

Post on 20-Dec-2015

218 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Operating Systems, 112 Practical Session 3 Threads 1

Operating Systems, 112

Practical Session 3 Threads

1

Page 2: Operating Systems, 112 Practical Session 3 Threads 1

Threads

• Executed within a process• Allow multiple independent executions under the

same process (container)• Possible states: running, ready, blocked, terminated. • In most of today’s operating systems, a process is

created with at least one thread but may have more than one thread (multithreading).

2

Page 3: Operating Systems, 112 Practical Session 3 Threads 1

Threads - Advantages

• Share open files, data structures, global variables, child processes, etc.

• Peer threads can communicate without using System calls

• Threads are faster to create/terminate/switch than processes (have no resources attached)

• Parallelism which improve overall performance:• A single core CPU and a substantial amount of

computing and I/O• Multiple cores

3

Page 4: Operating Systems, 112 Practical Session 3 Threads 1

Threads - Disadvantages

• Share open files, data structures, global variables, child processes, etc.

• No protection between threads – one can read/write/wipe out/corrupt the other’s data

• Sending some signals (such as SIGSTOP) to a process affects all threads running within it.

4

Page 5: Operating Systems, 112 Practical Session 3 Threads 1

Threads vs. Processes(“classic” approach – Linux’s clone results in some ambiguity)

Threads Processes

shared data unique data

shared code unique code

shared open I/O unique open I/O

shared signal table unique signal table

unique stack unique stack

unique PC unique PC

unique registers unique registers

unique state unique state

light context switch heavy context switch

Signal handlers must be shared among all threads of a multithreaded application; however, each thread must have its

own mask of pending and blocked signals (POSIX 1003.1).

5

Page 6: Operating Systems, 112 Practical Session 3 Threads 1

Threads- motivation

Web page cache

Workers

Dispatcher

Webpage request

Dispatcher thread:while (TRUE) { get_next_request(&buf); handoff_work(&buf);}

Worker thread:while (TRUE) { wait_for_work(&buf); look_for_page_in_cache(&buf, &page); if (page_not_in_cache(&page)) read_page_from_disk(&buf, &page); return page(&page); }

Example from “Modern Operating Systems”, 2nd Edition, pg. 88

Why are threads better in this case?

6

Page 7: Operating Systems, 112 Practical Session 3 Threads 1

Threads – some known Issues

• Does the fork() command duplicate just the calling thread or all threads of the process? – OS dependent; many UNIX systems implement both types

of fork() (e.g. Solaris 10).

• Does the exec() command replace the entire process?– The entire process is replaced including all its threads.

7

Page 8: Operating Systems, 112 Practical Session 3 Threads 1

User-level and Kernel-level ThreadsUser-level Threads Kernel-level Threads

P1 P2

User space

Kernel space Kernel

Scheduler

Scheduler

Scheduler8

Page 9: Operating Systems, 112 Practical Session 3 Threads 1

User-level threads

• The kernel sees just the main thread of the process (all other threads that run within the process’ context are “invisible” to the OS)

• The user application – not the kernel – is responsible for scheduling CPU time for its internal threads within the running time scheduled by the kernel to it.

9

Page 10: Operating Systems, 112 Practical Session 3 Threads 1

User-level threads (cont’d)

• The kernel’s inability to distinguish between user level threads makes it difficult to design preemptive scheduling for such thread. • When context switching is made directly towards the

entire process, clock interrupts are usually used for this purpose.

User level thread will usually have to voluntarily give up the CPU.

• If a thread makes a blocking system call, the entire process is blocked.

• Will only utilize a single CPU.10

Page 11: Operating Systems, 112 Practical Session 3 Threads 1

Kernel-level threads

• All threads are visible to the kernel.• The kernel manages the threads.

• The kernel schedules each thread within the time-slice of each process.

• The user cannot define the scheduling policy.• Context switching is slower for kernel threads than

for user-level threads.• Because the kernel knows about the threads, in

multiple CPU machines, each CPU can run a different thread of the same process, at the same time.

11

Page 12: Operating Systems, 112 Practical Session 3 Threads 1

Kernel-level threads User-level threads

Visible to the kernel Invisible to the kernel Threads

Kernel defined User defined Scheduling policy

Preemptive Non-preemptive* Thread switching

Slower, done by the kernel Faster, done by the runtime Context switch

Block the single thread Block the whole process Blocking calls

Held by the kernel Held by the process Thread table

User-level vs. kernel-level threads

12

Page 13: Operating Systems, 112 Practical Session 3 Threads 1

A tech. note on POSIX threads

• When the first Unix and POSIX functions were designed it was assumed that there will be a single thread of execution.

• Consider a naïve implementation of errno in a multi threaded environment for example. – Hence, the need for reentrant functions.– While this is supported by many standard functions, the

compiler must be aware of the need for re-entrant functions:

• gcc –D_REENTRANT –lpthread …

13

Page 14: Operating Systems, 112 Practical Session 3 Threads 1

Threads in POSIX (pthreads)int pthread_create( pthread_t* thread, pthread_attr_t* attr, void* (*start_func)(void*) , void* arg)Creates a new thread of control that executes concurrently with the calling thread.

On success, the identifier of the newly created thread is stored in the location pointed by the thread argument, and a 0 is returned. On error, a non-zero error code is returned.attr specifies thread attributes that will be applied to the new thread (e.g. detached, scheduling-policy). Can be NULL (default attributes).start_func is pointer to the function the thread will start executing; start_func receives one argument of type void* and returns a void*. arg is the parameter to be given to func.

pthread_t pthread_self()

return this thread’s identifier.

14

Page 15: Operating Systems, 112 Practical Session 3 Threads 1

Threads in POSIX (pthreads) – cont.int pthread_join( pthread_t th, void** thread_return )

Suspends the execution of the calling thread until the thread identified by th terminates.On success, the return value of th is stored in the location pointed by thread_return, and a 0 is returned. On error, a non-zero error code is returned.At most one thread can wait for the termination of a given thread. Calling pthread_join on a thread th on which another thread is already waiting for termination returns an error. th is the identifier of the thread that needs to be waited for

thread_return is pointer to the returned value of the th thread (can be NULL).

void pthread_exit( void* ret_val )

Terminates the execution of the calling thread. Doesn’t terminate the whole process if called from the main function.If ret_val is not null, then ret_val is saved, and its value is given to the thread who performed join on this thread; that is, it will be written to the thread_return parameter in the pthread_join call.

15

Page 16: Operating Systems, 112 Practical Session 3 Threads 1

Hello World!#include <pthread.h>

#include <stdio.h>

 

void *printme() {

printf("Hello World!\n");

return NULL;

}

 

void main() {

pthread_t tcb;

void *status;

if (pthread_create(&tcb, NULL, printme, NULL) != 0) {

perror("pthread_create");

exit(1);

}

if (pthread_join(tcb, &status) != 0) {

perror("pthread_join");

exit(1);

}

}

When compiling a multi-threaded app:gcc –D_REENTRANT –o myprog myprog.c –lpthread

What can happen if we remove the join part?

16

Page 17: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 1void *printme(void *id) { int *i; i = (int *)id; printf("Hi. I'm thread %d\n", *i); return NULL;}

void main() { int i, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); } for (i = 0; i < 4; i++) { printf("Trying to join with tid%d\n", i); pthread_join(tids[i], &retval); printf("Joined with tid%d\n", i); }}

17

Page 18: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 1possible outputTrying to join with tid0 Hi. I'm thread 0 Hi. I'm thread 1 Hi. I'm thread 2 Hi. I'm thread 3 Joined with tid0 Trying to join with tid1 Joined with tid1 Trying to join with tid2 Joined with tid2 Trying to join with tid3 Joined with tid3 18

Page 19: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 2void *printme(void *id) { int *i; i = (int *)id; printf("Hi. I'm thread %d\n", *i); pthread_exit(NULL);}

void main() { int i, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); } for (i = 0; i < 4; i++) { printf("Trying to join with tid%d\n", i); pthread_join(tids[i], &retval); printf("Joined with tid%d\n", i); }

pthread_exit(NULL);} 19

Page 20: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 2possible outputTrying to join with tid0 Hi. I'm thread 0 Hi. I'm thread 1 Hi. I'm thread 2 Hi. I'm thread 3 Joined with tid0 Trying to join with tid1 Joined with tid1 Trying to join with tid2 Joined with tid2 Trying to join with tid3 Joined with tid3 20

Page 21: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 3void *printme(void *id) { int *i; i = (int *)id; printf("Hi. I'm thread %d\n", *i); pthread_exit(NULL);}

void main() { int i, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); }

pthread_exit(NULL); for (i = 0; i < 4; i++) { printf("Trying to join with tid%d\n", i); pthread_join(tids[i], &retval); printf("Joined with tid%d\n", i); }} 21

Page 22: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 3output

Hi. I'm thread 0 Hi. I'm thread 1 Hi. I'm thread 2 Hi. I'm thread 3

If the main thread calls pthread_exit(), the process will continue executing until the last thread terminates or the process is terminated

22

Page 23: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 4void *printme(void *id) { int *i = (int *)id; sleep(5); printf("Hi. I'm thread %d\n", *i); pthread_exit(NULL);}

int main() { int i, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); }

return 0;}

23

Page 24: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 4possible output

No Output!

24

Page 25: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 5void *printme(void *id) { int *i; i = (int *)id; printf("Hi. I'm thread %d\n", *i); exit(0);}

main() { int i, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); }

for (i = 0; i < 4; i++) { printf("Trying to join with tid%d\n", i); pthread_join(tids[i], &retval); printf("Joined with tid%d\n", i); }

pthread_exit(NULL);} 25

Page 26: Operating Systems, 112 Practical Session 3 Threads 1

Example A – Version 5possible output

Trying to join with tid0 Hi. I'm thread 0

26

Page 27: Operating Systems, 112 Practical Session 3 Threads 1

Threads in XV6 (Assignment 2)

• XV6 doesn’t support threads.• Only processes can be created using the fork()

system call.• Thread support can be added to XV6:

– Implementing the clone(…) system call.– Configuring clone(…) to create a process with the same

memory space as its parent process.– Adding some basic threads functionality (create,

terminate, join…)

27

Page 28: Operating Systems, 112 Practical Session 3 Threads 1

Thread-specific data

• Programs often need global or static variables that have different values in different threads: Thread-specific data (TSD).

• Each thread possesses a private memory block, the TSD area.

• This area is indexed by TSD keys (Map).• TSD keys are common to all threads, but the

value associated with a given TSD key can be different in each thread.

• Defined in POSIX.28

Page 29: Operating Systems, 112 Practical Session 3 Threads 1

Thread-specific data – cont.

• Question: Why can’t we achieve this by using regular variables?

• Because threads share one memory space.• Example: separate log for each thread.

29

Page 30: Operating Systems, 112 Practical Session 3 Threads 1

Thread-specific data – cont.int pthread_key_create(pthread_key_t* key, void (*destr_func)(void*))

Allocates a new TSD key. Return 0 on success and a non-zero error code on failure.

key the key is stored in the location pointed to by key.

destr_func if not NULL, specifies a destructor function associated with the key. When a thread terminates via pthread_exit, destr_func is called with arguments – the value associated with the key in that thread. The order in which destructor functions are called at thread termination time is unspecified.

int pthread_key_delete(pthread_key_t key)

Deallocates a new TSD key. Return 0 on success and a non-zero error code on failure.

It does not check whether non-NULL values are associated with that key in the currently executing threads, nor call the destructor function associated with the key.key the key of the value to delete.

30

Page 31: Operating Systems, 112 Practical Session 3 Threads 1

Thread-specific data – cont.

int pthread_setspecific(pthread_key_t key, const void* pointer)

Changes the value associated with key in the calling thread, storing the given pointer instead.

void* pthread_getspecific(pthread_key_t key)

Returns the value currently associated with key in the calling thread, or NULL on error.

31

Page 32: Operating Systems, 112 Practical Session 3 Threads 1

Example B (1)#include <pthread.h> #include <stdio.h> #include <stdlib.h>

typedef struct info {

int position; } info_t;

static pthread_key_t tsdKey = 0; int g1; int gArr[3];

void globalDestructor(void *value) {

printf("In the data destructor\n"); if (value != NULL)

free(value); pthread_setspecific(tsdKey, NULL);

}

32

Page 33: Operating Systems, 112 Practical Session 3 Threads 1

Example B (2)void increaseInArray(int val) {

// Read position from TSD, and increase the array info_t *myData = pthread_getspecific(tsdKey); gArr[myData->position] += val; printf("Thread %d is increasing position %d by %d\n",

pthread_self(), myData->position, val); }

void *funcA(void *arg) {

int* pPos = (int *)arg; int pos = *pPos; // Allocate memory for TSD info_t *myData = (info_t *)malloc(sizeof(info_t)); myData->position = pos; pthread_setspecific(tsdKey, myData);

increaseInArray(pthread_self()); return NULL;

}33

Page 34: Operating Systems, 112 Practical Session 3 Threads 1

Example B (3)void *funcB(void *arg) {

int local = 29; printf("Thread %d: local=%d, g1=%d\n",

pthread_self(), local, g1); g1 = 90; pthread_exit(NULL);

}

int main() {

pthread_t t1, t2, t3; int pos1 = 0, pos2 = 1; int local = 15;

// ... g1 = 7;

pthread_key_create(&tsdKey, globalDestructor); printf("Thread main id %d\n", pthread_self());

34

Page 35: Operating Systems, 112 Practical Session 3 Threads 1

Example B (4)printf("Creating two threads\n"); pthread_create(&t1, NULL, &funcA, &pos1); pthread_create(&t2, NULL, &funcA, &pos2);

printf("Waiting for two threads\n"); pthread_join(t1, NULL); pthread_join(t2, NULL);

printf("Creating another thread\n"); pthread_create(&t3, NULL, &funcB, NULL); pthread_join(t3, NULL);

printf("The array is: %d, %d\n", gArr[0], gArr[1]); printf("Thread %d: local=%d, g1=%d\n", pthread_self(), local, g1);

pthread_key_delete(tsdKey); return 0;

}

35

Page 36: Operating Systems, 112 Practical Session 3 Threads 1

Example Bpossible outputThread main id 1024Creating two threadsThread 1026 is increasing position 0 by 1026In the data destructorThread 2051 is increasing position 1 by 2051In the data destructorWaiting for two threadsCreating another threadThread 3074: local=29, g1=7The array is: 1026, 2051Thread 1024: local=15, g1=90

36

Page 37: Operating Systems, 112 Practical Session 3 Threads 1

Midterm – 2006

37

מצביע על g. קודקוד בעץ תהליכים כל קודקוד מייצג תהליך.q יצר את g, כלומר אם q הוא אבא של g אם"ם qקודקוד

g

q

שרטטו את עץ התהליכים הנוצר ע"י )א( . (תנו שמות Cהרצת הקוד הבא בשפת

;int x .1שרירותיים לתהליכים הנוצרים.)2. fork();3. x = fork();4. if(x != 0)6. fork();7. printf(“pid= %d”,getpid());

Page 38: Operating Systems, 112 Practical Session 3 Threads 1

Midterm – 2006 (cont’d)

38

2

36

45

1

:פתרון )א(

Page 39: Operating Systems, 112 Practical Session 3 Threads 1

Midterm – 2006 (cont’d)

39

ב. מהו הפלט של הרצת התוכנית מסעיף א'? האם זהו הפלט היחיד

שורות). 3 האפשרי? הסבירו. (עד  

. הפלט אינו יחיד, כל 0שישה מספרים גדולים מ :פתרון )ב( מספרים נכוניםשישה

  

;kill(x, SIGINT). 5 נוסיף את השורה: 6 ו 4ג. אם בין שורות מה ישתנה בעץ התהליכים ובפלט?

  ימותו. הפלט עשוי להישאר זהה או 4 ו 3: התהליכים פתרון )ג( 

מספרים4 מספרים או רק 5 שיודפסו רק

Page 40: Operating Systems, 112 Practical Session 3 Threads 1

Midterm – 2006 (cont’d)

40

ד. האם ייתכן תסריט שבו לאחר השינוי נקבל פלט זהה לפלט אותו קיבלנו לפני השינוי? אם כן, מהו תסריט זה? אם לא, נמקו

מדוע לא יתכן כי נקבל פלט זהה. 

: כן יתכן כזה תסריט. נניח שהמתזמן נותן לכל בן שנוצר פתרון )ד(ב-

fork לרוץ עד אשר הוא מסיים הרי שכל אחד יספיק להגיע לשורת ההדפסה.   

Page 41: Operating Systems, 112 Practical Session 3 Threads 1

Midterm – 2006 (cont’d)

41

, שתרוץ על threadsה. נניח כי תידרשו לכתוב תוכנית מרובת kernel וגם ב-user threadsמערכת הפעלה התומכת גם ב-

threads-באיזו אפשרות תבחרו אם ה .threads מבצעים פעולות I/O שורות). הסבירו באילו נסיבות (כלומר, 3 רבות? הסבירו (עד

עבור איזה סוג תוכנית) הייתם בוחרים באפשרות השנייה. 

כולם לעבור ל user threads גורמת ל I/O: פעולת פתרון )ה(blocking שכן מערכת ההפעלה לא מודעת לקיומם ולכן לא

. I/O סביר לבחור באופציה זו במקרה של ריבוי פעולות במקרים user threads לעומת זאת, כדאי לבחור ב

בהם רוצים למשל שליטה מלאה על התזמון. בנוסף, אם

מדובר user threads במערכת עם יחסית מעט מעבדים נעדיף

שכן החלפה ביניהם היא מהירה יותר.