Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Linux questions using c and shell bash programs. Make files: lab05q1.c, lab05q2.c DBserver.c contains a RACE CONDITION on variable total_queries As demonstrated in class, the

Linux questions using c and shell bash programs.

Make files: lab05q1.c, lab05q2.c

DBserver.c contains a RACE CONDITION on variable total_queries As demonstrated in class, the program does not always calaulate total_queries as 3036; it is sometimes less than 3036 because of the race condition. Shell program runDBserver.sh runs it 100 times, and usually finds at least one run manifesting the race condition. Note that DBserver.c uses "threads" managed by the kernel (OS).

1. Copy DBserver.c into a file in your filespace named lab05q1.c Modify lab05q1.c so that it has the same functionality as DBserver.c except that it uses pthreads for its threads.

"Clean up" your new code to make it more clear and concise. - you can join threads much more simply. Actually, you HAVE to, given this statement from "man pthread_join": There is no pthreads analog of waitpid(-1, &status, 0), that is, "join with any terminated thread". If you believe you need this functionality, you probably need to rethink your application design. Verify that the same race condition can also occur in your lab05q1.c i.e., run it until you see it print the "wrong" output. You might want to use a modified version of runDBserver.sh

2. Read about MUTEXES in: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SYNCHRONIZATION You only need to read the MUTEX part for this lab.

Copy your file lab05q1.c to lab05q2.c, and then modify lab05q2.c to eliminate the race condition by using an appropriate mutex.

Verify your program will always correctly print 3036 when it is run 100 times in a row, using a modified version of runDBserver.sh

/* 3 users use the DB (for each, a thread is spawned). Thread i does queryNo[i] queries for its user. A global "total_queries" is maintained. Each thread updates it after each of its queries.

This has a race condition on variable total_queries.

Note that if you have maxed out your allotted clones, one (or more) child may never execute its function, although it exists. So parent can't terminate because it waits forever for child (do ps -l or ps -lu USERID and kill the offending child) */

#define _GNU_SOURCE //for Ubuntu #include #include #include #include #include #include #include #include

int queryNo[3] = {1011, 1012, 1013};

int total_queries = 0;

int userThread (void *p) { int i; int q = (int)(long)p;

//set thread q on CPU q cpu_set_t set; CPU_ZERO( &set ); CPU_SET( q, &set ); if (sched_setaffinity( getpid(), sizeof( cpu_set_t ), &set )) { perror( "sched_setaffinity" ); _exit(0); }

for (i = 0; i < queryNo[q]; i++) { //handle queries total_queries = total_queries + 1; } _exit(0); }

int main(int argc, char *argv[]) { const int STACK_SIZE = 65536; char *stack; char *stackTop[3]; pid_t cret[3], wret; int i;

for (i = 0; i < 3; i++) { //do 3 child threads stack = malloc(STACK_SIZE); if (stack == NULL) { perror("malloc"); exit(1); } stackTop[i] = stack + STACK_SIZE; /* Assume stack grows downward */

cret[i] = clone(userThread, stackTop[i], CLONE_VM|SIGCHLD, (void *)(long)i); //make child signal when done

if (cret[i] == -1) { perror("clone"); exit(0); } //parent keeps going here } //for (i=0;i<3;i++) waitpid(cret[i],0,0);

for (i = 0; i < 3; i++) { wret = waitpid(-1, 0, 0); if (wret == -1) { perror("waitpid"); exit(3); } //a useless double-check that we got our own children... if (wret != cret[0] && wret != cret[1] && wret != cret[2] ) { perror("waitpid wret"); exit(2); } } sleep(1); printf("%d total_queries should be 3036 and it is %d ", getpid(), total_queries); return 0; }

#!/bin/bash #sometimes you might get 1 out of these that is not 3036 #if it is 3036, nothing printed. If not, it prints the value for i in {1..100} ; do echo "$i. " DBserver 2>/dev/null | grep -v "it is 3036" done

#Here are results from a recent run of #/usr/courses/cps590/Programs/race_condition: runDBserver.sh # I killed it prematurely, but you get the idea: # #1. #2. #3. #4. #5. #6. #7. #1338291 total_queries should be 3036 and it is 2994 #8. #9. #10. #11. #12. #13. #14. #15. #16. #17. #18. #19. #20. #21. #1338325 total_queries should be 3036 and it is 2887 #22. #23. #24. #25. #26. #27. #1338357 total_queries should be 3036 and it is 3010 #28. #29. #1338367 total_queries should be 3036 and it is 3021 #30. #31. #32. #33. #34. #35. #36. #37. #38. #39. #40.

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started