OS_HW_04_F2020 Assignment Four: Synchronization Support and pthreads EECE 4029: Operating Systems and Systems Programming ELTN 4022: Operating Systems Department of Electrical Engineering and Computer...

1 answer below »

Synchronization Support and pthreads




OS_HW_04_F2020 Assignment Four: Synchronization Support and pthreads EECE 4029: Operating Systems and Systems Programming ELTN 4022: Operating Systems Department of Electrical Engineering and Computer Science University of Cincinnati, Cincinnati OH Revision Date: Oct 07, 2020 Purpose In this assignment, you will become more familiar with multithreading as implemented by the pthreads library and you will explore the benefits and drawbacks of various synchronization primitives. a) You will write basic multithreaded code and examine the occurrence of and the causes of race conditions. This will serve as a practical code supplement to concepts discussed in lecture. b) You will use mutexes, semaphores, and spinlocks to sequence memory operations to prevent race conditions. You will also examine and learn about the various benefits and drawbacks to each choice. c) You will use one or more of the discussed synchronization primitives to implement a “readers- writer lock” – another type of synchronization primitive. Activity Summary This assignment is worth 100 points and is broken into two parts: Activity Set A (50 points): A number of guided programming exercises with discussion questions which all together are worth 50 points. You may work on these guided programming exercises in small groups, but you must make your own writeup of the results of these exercises and turn that in as part of this assignment. Activity Set B (50 points): You will write your own set of subroutines to implement “readers- writer locks” using existing primitives. You will be required to demonstrate that your implementation functions by linking your code to a multi-threaded test application that will be provided. The test application must run without race conditions or locking of any kind. The text describing your specific deliverables is given in line with the narrative writeup and is rendered in green text. Included with this narrative writeup is a MS Word format answer sheet template that contains all of the green text questions and space for you to fill in your answers. Please use that template to produce a single PDF containing your Activity Set A answers. Your activity set B answer should be a single C code source file containing the source code of your readers-writer lock library. This source file should be commented in detail to explain what you are doing and why. Please refer to the answer template file for more details on how to format and submit your answers. Activity Set A: Guided Programming Exercises (50 points total for Activity A) Activity A, Task 1: Race Condition Example (10/40 points) In class, we would have discussed the basics of multi-threading and race conditions. Here we’ll briefly summarize the highlights of those conversations and introduce some code that does, indeed, spawn multiple threads. The code we talk about in this activity will NOT properly protect its own critical section and will be somewhat susceptible to race conditions. In subsequent activity A tasks, we’ll introduce various synchronization primitives as a means to prevent the improper racing behaviors. Note that sample code below is TERRIBLE and is VERY unsafe. It will be rife with race conditions and actual outputs will not be predictable because order of operations on shared memory will not be guaranteed. This code is terrible on purpose. Once we look at it, how it’s terrible, and why, we’ll fix it. #include #include #include // This is the header file that contains prototypes for // pthreads structures and user functions int c = 0; // I'm declaring a global variable. The memory for this variable // will be in the process DATA segment and will have global scope. // Every thread that accesses this variable will be accessing the // exact same value in the same memory spot in the data segment. // Naturally, this is potentially dangerous and could be a cause // of race conditions if there is more than one thread trying // to write or read and write at the same time. // The way threads work is that we "register" a function as a thread. Once // the function is "registered" and "launched" -- it will run LIKE a process // in that it will be scheduled like one, but it will share the same text, data, // and heap segments with EVERY OTHER thread launched in the same process. // Sometime threads are referred to as "lightweight processes". This kind of makes // sense. It allows parallelism and multi-programming across multiple lines of // execution, but does not require full context switches in which the whole process // memory map is spun down and the whole process put into a wait state whenever // a context switch occurs. Threads can be scheduled and suspended with far less // overhead. // // Now, if you look at this code, you may note that I'm defining it with a * // in front of the name. This essentially means that the token fnC is actually // a POINTER to the function while *fnc() is actually a CALL to the function. // Pointers to functions are actually kind of cool and you may want to review // them if you are not familiar with them. We'll use it here so we can tell // one function (the pthreads routine that registers and launches threads) that // the thread should RUN the code that lives at the end of a function pointer. // // The function itself is kind of simple. It just counts from zero to nine and // for each step it increments the global variable "c" and then prints the value // to the screen. Now, if I were to make two calls to *fnC() as NORMAL functions, // not threads, this would print the following: // // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // // Of course, a naive programmer might think that if I were to run fnC() as two // threads, I'd get the same result -- but potentially "faster" because of // multiple cores. Of course, you already know this won't happen :) void *fnC() { int i; for(i=0;i<10;i++) {="" c++;="" printf("="" %d",="" c);="" }="" }="" int="" main()="" {="" these="" will="" be="" return="" values="" from="" the="" routine="" that="" launches="" threads="" int="" rt1,="" rt2;="" these="" are="" variables="" of="" pthread_t,="" they="" hold="" bookkeeping="" values="" for="" threads.="" in="" this="" case="" we’ll="" launch="" two="" threads,="" so="" we="" need="" two="" of="" these.="" pthread_t="" t1,="" t2;="" we’re="" going="" to="" run="" a="" bunch="" of="" thread="" experiments="" and="" examine="" the="" outputs.="" this="" variable="" will="" keep="" track="" of="" which="" trial="" we’re="" on.="" int="" trial_count="0;" for="" every="" trial,="" lets="" zero="" out="" the="" counter="" and="" run="" the="" count="" routine="" “twice”="" as="" threads="" that="" can="" be="" scheduled="" onto="" independent="" cores="" instead="" of="" running="" in="" sequence.="" for="" (trial_count="0;" trial_count="">< 1000; trial_count++) { // zero out the global counter c = 0; // create two thread with the routine pthread_create(). you can use // reference materials to get definitions of what the various parameters // mean. if((rt1=pthread_create( &t1, null, &fnc, null))) printf("thread creation failed: %d\n", rt1); if((rt2=pthread_create( &t2, null, &fnc, null))) printf("thread creation failed: %d\n", rt2); // wait for both threads to finish. the main process thread will block // until the threads that were launched terminate. once they both finish, // then the “main thread” unblocks and continues. pthread_join(t1, null); pthread_join(t2, null); printf("\n"); } return 0; } you may at this point wish to compile and run the above code. examine, carefully, the lines of output you get. often the output will be what you would have expected if *fn(c) were run twice, serially, as standard function calls. sometimes, however, you will not. after you run and examine some outputs, complete the following discussion questions: activity a, task 1000;="" trial_count++)="" {="" zero="" out="" the="" global="" counter="" c="0;" create="" two="" thread="" with="" the="" routine="" pthread_create().="" you="" can="" use="" reference="" materials="" to="" get="" definitions="" of="" what="" the="" various="" parameters="" mean.="" if((rt1="pthread_create(" &t1,="" null,="" &fnc,="" null)))="" printf("thread="" creation="" failed:="" %d\n",="" rt1);="" if((rt2="pthread_create(" &t2,="" null,="" &fnc,="" null)))="" printf("thread="" creation="" failed:="" %d\n",="" rt2);="" wait="" for="" both="" threads="" to="" finish.="" the="" main="" process="" thread="" will="" block="" until="" the="" threads="" that="" were="" launched="" terminate.="" once="" they="" both="" finish,="" then="" the="" “main="" thread”="" unblocks="" and="" continues.="" pthread_join(t1,="" null);="" pthread_join(t2,="" null);="" printf("\n");="" }="" return="" 0;="" }="" you="" may="" at="" this="" point="" wish="" to="" compile="" and="" run="" the="" above="" code.="" examine,="" carefully,="" the="" lines="" of="" output="" you="" get.="" often="" the="" output="" will="" be="" what="" you="" would="" have="" expected="" if="" *fn(c)="" were="" run="" twice,="" serially,="" as="" standard="" function="" calls.="" sometimes,="" however,="" you="" will="" not.="" after="" you="" run="" and="" examine="" some="" outputs,="" complete="" the="" following="" discussion="" questions:="" activity="" a,="">
Answered 177 days AfterOct 14, 2021

Answer To: OS_HW_04_F2020 Assignment Four: Synchronization Support and pthreads EECE 4029: Operating Systems...

Karthi answered on Apr 09 2022
106 Votes
SOLUTION.PDF

Answer To This Question Is Available To Download

Related Questions & Answers

More Questions »

Submit New Assignment

Copy and Paste Your Assignment Here