Objectives ▪ Review on fork() and exec() – Some issues on forking and exec-ing ▪ POSIX Threads ▪ Lab 8
Review on Forking and Exec-ing ▪ Both of them create child processes ▪ However, their natures are different – Forks create child processes and both of them work concurrently – Execs create child processes, but parent is overwritten by child (meaning, they can’t exist at the same time) ▪ Illustration of fork and exec
Problem with forking/exec-ing ▪ Child process almost duplicates everything – Only data shared by parent and child is file descriptor (includes pipes and sockets) ▪ Why fork()? – No threads back then! (because of single processors) ▪ Implication: one process had one “thread” (a heavyweight process) – Pipes were still useful for processes that needed to communicate to each other – Processes could load variables with data, fork, then go back doing other stuff while child does the work ▪ Which is done by daemons ▪ In short, parents like making the children work
Threads ▪ Java allows users to create threads (lightweight processes) that can work concurrently on same data and rely on same memory copy of code – Meaning that data is not just processed for one process, but having two threads process data will result into faster results, but of course with synchronization issues (not gonna discuss this)
POSIX Threads (Pthreads) ▪ Works almost like threads in Java ▪ Much harder to use than Java threads (because Java only deals with JVM, while pthreads handle already processes; remember: Unix is NOT a virtual machine) ▪ Only works in systems that support it (Ubuntu/Fedora Linux) ▪ Much harder to use than fork() and exec()
How to use PThreads ▪ #include ▪ Optional library to add: -lpthread ▪ Pthreads have same issues as threads in Java, like synchronization, race conditions, etc. ▪ Example of PThread posted in Moodle
pthread_create() ▪ Arguments – 1: Pointer to / address of pthread_t ▪ Note: pointers are ints that contain addresses! – 2: Pointer to struct pthread_t (not usually important, so it’s always NULL) – 3: Pointer to thread’s run() function ▪ Function should only have one argument, preferably void * ▪ Function should be of type void * – 4: Pointer to function’s argument
Void Pointers (void *) ▪ In Java, everything (except primitives) is an Object and a pointer – All classes extend Object – Object o; //can point to a string – Casting is needed to use methods from actual class ▪ void * is a pointer to ANYTHING, including primitives – Casting still needed (to void * during thread creation and back to int * in entry function) – Because it’s a pointer, you can cast it to its pointer value (int) ▪ Allows call-by-value arguments (local variable) instead of call-by-reference (changes are permanent after function returns)
Advantages of PThreads ▪ Pthreads will have same access variables as parent (like forks) ▪ These variables are just the same – If a Pthread changes the variables, parent process and other pthreads will be able to see (and edit) the changes
Implementing More Pthreads ▪ Use malloc pthread *arr = malloc(sizeof(pthread_t) * N); – where N is the number of threads ▪ Create a whole bunch of pthreads in for loop using pthread_create() ▪ The process that created these threads will still run afterwards – Block the parent process first or else it will either ▪ Terminate prematurely ▪ Or run in incorrect fashion – sleep() is not a good idea about this… (we don’t know when other threads will finish, so by sleeping, it will terminate the entire process, affecting the threads)
Waiting for Thread to Finish // from where we left off // after creating the thread... retval = pthread_join( myThread, NULL ); // process will now block at this point // until the Pthread specified is done.
pthread_join() ▪ Arguments – 1: Pointer to address of a pthread_t (like pthread_create()) – 2: Pointer to what will contain the exit-return value function ▪ NULL if you don’t need it ▪ Else, it is used when pthread_exit() is called ▪ Returns 0 if successful!
Other Functions ▪ Note: these are called from INSIDE a pthread ▪ pthread_self() – Returns ID of pthread – Useful because pthread_create() does not return the pthread’s ID (only 0 or error) ▪ Pthread_exit(void * retval) – Terminates thread – Returns pointer argument to the next pthread_join() handling this thread – Local variables can’t be used here since they are wiped out when thread terminates
Other Functions ▪ Pthread has many more functions, but for now, we will be dealing with pthread_create() and pthread_join() ▪ For more information on these threads, visit the following site: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
Lab 8: sine.c ▪ Create a C program that creates an ARBITRARY number of pthreads to compute sine(x) – These threads should access the same entry function ▪ You are not allowed to make one function for each thread – Because you suppport arbitrary number of threads – Defeats the purpose of having multiple threads ▪ Program usage:./sine N X – N = number of threads (should be greater than 0) – X = argument for the sine function //sine(x) was used to avoid conflict with the sin() function of math.h in C
Lab 8: sine.c ▪ Note: the sin() function of C computes sin() in RADIANS! So the sine function you will build should also be in RADIANS (meaning, between –PI and PI) – Pi value is up to you, however. But for maximum precision, at least 10 decimal places of PI should suffice ▪ The sine(x) function is given by this infinite series: – sine(x) = (x / 1!) – (x^3 / 3!) + (x^5 / 5!) – (x^7 / 7!) + … – Term number: 0, 1, 2, 3 … – Note: ^ means power, not XOR ▪ Each thread will compute enough terms assigned to them until the last computed term has absolute value less than 10^(-16)
Lab 8: sine.c ▪ For all necessary computations, use the type “long double” for extremely large or high-precision numbers to be contained ▪ Output the value of sine(x) in console! – You can compare the output of your sine(x) with the sin(x) function of C. just include math.h in your libraries and add –lm when compiling ▪ Suggestion: you may want to add a sleep(1) and printf() checks in whatever loop the threads access to check if they are being run really in parallel
Lab 8: sine.c ▪ You should also handle argument errors and issues, like 0 or fewer threads, or incomplete argument issues. – For X, suggestion is that the value should range from –PI to PI. I won’t really be strict with this ▪ A global variable is probably needed long double *sum; sum = malloc(sizeof(long double) * N); ▪The purpose of this is that thread 0 can save its computed sum in sum, thread 1 in sum, etc. sine(x) = sum + sum + sum + …
Lab 8: sine.c ▪For a 4-thread example, thread-0 should be able to compute the terms with x, x^9, x^17, etc (terms, 0, 4, and 8, respectively) ▪Example (written on the board) ▪Legalities – Include a Certificate of Authorship (with signature in it, and other COMPLETE details) – Filename: CS162B_Lab8_ _ _.tar – Deadline: Next week (Tuesday for Section A, Thursday for Section B)
Your consent to our cookies if you continue to use this website.