Vous êtes sur la page 1sur 4

Page 1 of 5

CS 336 : Multiprocessing vs. Multithreading 1. The goal of todays exercise is to experiment compare and contrastMultipr ocessing vs. Multithreading. 2. Login to one of the PCs in the department. Startup PuTTY from the Application Shortcuts folder, and connect to themat h.l f c.edu server; recall that if you want to make the font larger, clickAppearanc e from theWi n d o w category (list along the left) and change the font before connecting. 3. To start, change directory (cd) to yourin- class directory, make a new directory (mkdir) named2-1-M ul t i t hreadi ng, and then cd into this directory. Next, copy two C files I have provided (notice the period . at the end of the command, that is necessary):
cp ~hummel/public/cs336/inclass/2-1/*.c .

This will copy 2 programs, main-mp.c and main-mt.c printouts of these programs are attached. The -mp is the Multiprocessing version, and the -mt is the Multithreading version. 4. Startup another instance of PuTTY, open another connection to math.lfc.ed u, and login to your account. Well use this second instance of PuTTY to monitor the list of running processes. Recall this is done using the Linuxtop command (substitute yourUSERN A ME forhumm el):
top -d 1.0 u hummel

5. Take a look at the multiprocessing version of the program main-mp.c (printout attached). Notice it declares a global variable, forks off a child process, and then both the parent & child increment this variable. Compile the program and run it (gcc main-mp.c, a.out). Recall that fork( ) makes a complete copy of the parent process, which is why the parent and child end up incrementing *different* global variables they each have their own copy. Also notice that the child and the parent both return back to the main method, and exit normally. Youll see two messages appear on the screen to that effect. 6. Lets convince ourselves that fork( ) yields two, independently-running processes. Change the code in the child method to loop forever i.e. replace the for loop with a while (1) loop. Recompile and run. Notice that the parent will eventually stop (after 10 iterations), but as expected, the child will run forever. Interestingly, we have a problem how to stop the child process? :-) Ctrl-C doesnt work, since the child process was forked off Over in your other PuTTY window, note the process id of the child process. Now ctrl-C to exit the top command, and kill the child process by entering kill -9 pid. This should terminate the child process (youll know when the output stops). Restart the top command when all is well 7. In some designs the parent process will fork off a child to perform background tasks, and In-class lab exercise: Thurs 2/1
Page 2 of 5

then kill the child just before it exits. This way the child process is not left hanging around. To do this, modify the parent method just before it returns to stop the child:
kill(pid, SIGKILL); // stop child process wait(&status); // wait for child to actually stop

Compile, run, and now the child process should be stopped automatically by the parent. Notice that now only the parent returns back to the main method and exits normally youll see only one output message to that effect. The child process was busy running an infinite loop when it was stopped, and so never gets a chance to exit the loop and return back to the main method. 8. Okay, lets witness one more important characteristic of multiprocessing: if the parent or child crashes, the other continues running. For example, lets introduce an error into the child process. Inside the infinite loop, when g is 10 then crash the child by executing the following code:
int *crashptr; // declare a ptr into memory crashptr = NULL; // point to an illegal memory location *crashptr = 123; // try to store 123 into that memory location!

Compile and run the child process will silently crash, while the parent keeps on running. This is one of the advantages of a multiprocessing approach. 9. Okay, lets take a look at the multithreaded version of this program main-mt.c (printout attached). This does exactly the same thing, except instead of using fork( ), it calls pthread_create to create a separate, child thread of execution. Unlike fork, which returns twice, the call topthrea d_create returns exactly once: it creates a thread to execute the function specified by the 3 rd parameter child( ) in this case and then returns immediately back to the caller so the calling thread (the parent) may continue executing. As a result, we end up with two threads of execution, parent and child, which execute concurrently. The design of pthread_create supports the general usage of threads, which is to execute smaller amounts of code, normally just a single function such as child( ). When that function ends (i.e. returns), the thread dies. 10. Compile the program as follows: gcc main-mt.c lpthread . The l option links in thept hread library (multithreading is not an inherent feature of the Linux OS). Run the program, and notice the following three characteristics that differ from the multiprocessing version:

The top command displays only one process running; the two threads reside in the same process.

Threads share memory, which is why the parent and child threads increment the *same* global variable.

When the child thread returns, it dies it never actually returns back to the main method. Youll see a message that the child is about to return, but you wont see the subsequent output message printed in the main method. Only the parent thread will return back to main and exit normally. In-class lab exercise: Thurs 2/1
Page 3 of 5

11. Next, as we did earlier, change the childsfor loop to an infinite loop such as while (1). Compile and run. In this case, even though the child is looping forever, notice that when the parent thread returns back to main and exits, the child thread is killed. In the world of multithreading, the parent thread is in charge, and when it stops, all threads stop. This is unlike

the world of multiprocessing, which creates distinct processes that run independently of each other. Of course, if the parent thread wants to stop a child thread, it does so in much the same way a parent process stops a child process. To do this, modify the parent method just before it returns to stop the child thread:
pthread_cancel(tid); // stop child thread pthread_join(tid, NULL); // wait for thread to actually stop

Compile, run, and now the child thread is stopped explicitly by the parent thread. 12. Lets witness one last critical difference between multiprocessing and multithreading if a thread crashes, all threads crash and the process hosting them terminates. Like we did earlier, lets intentionally crash the child. Inside the childs infinite loop, when g is 10 then crash the child thread by executing the following code:
int *crashptr; // declare a ptr into memory crashptr = NULL; // point to an illegal memory location *crashptr = 123; // try to store 123 into that memory location!

Compile and run the child thread will now crash, bringing down the entire processes. This is one of the disadvantages of a multithreaded approach. Thats it for today, good work!
Page 4 of 5
/* main-mp.c : simple multiprocessing with 2 processes */ #include <stdio.h> #include <unistd.h> #include <signal.h> void *child(void *); // function prototypes

void *parent(void *);

int g = 0; // global variable

int main() { int pid;

signal(SIGCHLD, SIG_IGN); // don't let children linger in process table

printf("## Notice parent & child are incrementing a different global. ##\n");

pid = fork(); if (pid == 0) child(NULL); else parent(&pid); printf("** Process %d has returned, about to exit...\n", getpid()); return 0; }void *child(void *p) { int i;

printf("** Child %d starting...\n", getpid()); for (i = 0; i < 20; i++) { sleep(1); g++; printf("-->child: %d\n", g); fflush(stdout); }printf("** Child about to return...\n"); return NULL; }void *parent(void *p) {

int i, status, pid;

pid = * ((int *) p); // retrieve child's pid

printf("** Parent %d starting...\n", getpid());

for (i = 0; i < 10; i++) { sleep(3); g++; printf("##>parent: %d\n", g); fflush(stdout); }printf("** Parent about to return...\n"); return NULL; }

Vous aimerez peut-être aussi