Problem 1: ---------- This problem does not *require* any kind of locking. Each location has only one writer and each location is written only once. As a result, synchronization can be easily achieved by using sentinel values (invalid ratings such as -1 which indicate that a location has not yet been written to). I have included four solutions in this file. The first and fourth use this sentinel value idea; the second uses a "turn" variable (whose turn is it) -- which does not need a lock either; the third one uses an array of semaphores. The final "solution" is NOT a solution of the problem as stated (as it does not maintain the upward and downward orders) -- but to a variant. These solutions handle only one proposal. -------------------------------------------------------------------------- Grading: -------- correct upward order: 5 points correct downward order: 5 points correct final results: 5 points (including local copy) Total: 15 points -------------------------------------------------------------------------- Solution 1: ----------- The key idea is to two arrays of integers: one to hold the ratings provided by individual officials and the other to hold each official's copy of the final rating. Elements in both these arrays are initialized to -1 (which is not a legal rating). int initialRating[K]; int finalRating[K]; Threads *officials[K]; void main() { for (i = 0; i < K; i++) { initRating[i] = -1; finalRating[i] = -1; officials[i] = new Thread(); officials[i]->fork(simOfficial, i); } /* set initRating[0] to 0 to start off the first official * 0 is used as it does not effect the final result */ initRating[0] = 0; waitForAllThreadsToComplete(); } void simOfficial(int id) { /* wait for the next lower official to mark her rating */ while (initRating[id] == -1) currentThread->yield(); /* now all officials below me have marked their ratings */ /* compute my rating - using a random value between 1 and 10 */ myRating = 1 + rand()%10; if (id == K-1) { /* if I am the final official, I add up everyone's ratings * and add my own; and set my finalRating cell */ for (sum = myRating, i = 0; i < K; i++) sum += initRating[i]; finalRating[id] = sum; } else { /* I just set my rating in the array and wait for my superiors * to be done */ initRating[id+1] = myRating; while (finalRating[id+1] == -1) currentThread->yield(); finalRating[id] = finalRating[id+1]; } } -------------------------------------------------------------------------- Solution 2: ----------- int initialRating[K]; int finalRating[K]; Threads *officials[K]; int turn = 0; void main() { for (i = 0; i < K; i++) { officials[i] = new Thread(); officials[i]->fork(simOfficial, i); } waitForAllThreadsToComplete(); } void simOfficial(int id) { /* wait till the turn is mine - note that once turn == id, * no other thread will modify turn */ while (turn != id) currentThread->yield(); /* now all officials below me have marked their ratings */ /* compute my rating - using a random value between 1 and 10 */ myRating = 1 + rand()%10; if (id == K-1) { /* if I am the final official, I add up everyone's ratings * and add my own; and set my finalRating cell */ for (sum = myRating, i = 0; i < K; i++) sum += initRating[i]; finalRating[id] = sum; } else { /* I just set my rating in the array, signal my superior and * wait for a signal from my superior */ initRating[id+1] = myRating; turn++; while (turn != id) currentThread->yield(); finalRating[id] = finalRating[id+1]; } /* signal my inferior */ turn--; /* since this is the last operation, leaving turn = -1 at end is ok */ } -------------------------------------------------------------------------- Solution 3: ----------- This solution uses semaphores to sequence the operations of all officials - one semaphore per official (you don't need separate semaphores for the two phases). Initially, all semaphores are set to 0. In the first phase, each thread signals its superior by performing a V() on its semaphore. In the second phase, each thread signals its inferior by performing a V() on its semaphore. Notice the similarity between this solution and Solution 1 where sentinel values in the initRating and finalRating arrays are used for the same purpose. Notice the similarity between this solution and the previous one. int initialRating[K]; int finalRating[K]; Threads *officials[K]; Semaphores *semaphores[K]; void main() { for (i = 0; i < K; i++) { semaphores[i] = new Semaphore(0); officials[i] = new Thread(); officials[i]->fork(simOfficial, i); } semaphores[0]->V(); waitForAllThreadsToComplete(); } void simOfficial(int id) { /* wait for signal from the inferior official */ semaphores[i]->P(); /* now all officials below me have marked their ratings */ /* compute my rating - using a random value between 1 and 10 */ myRating = 1 + rand()%10; if (id == K-1) { /* if I am the final official, I add up everyone's ratings * and add my own; and set my finalRating cell */ for (sum = myRating, i = 0; i < K; i++) sum += initRating[i]; finalRating[id] = sum; } else { /* I just set my rating in the array, signal my superior and * wait for a signal from my superior */ initRating[id+1] = myRating; semaphores[id+1]->V(); semaphores[id]->P(); finalRating[id] = finalRating[id+1]; } /* signal my inferior */ if (id > 0) semaphores[id-1]->V(); } -------------------------------------------------------------------------- Solution 4: ----------- An even simpler solution is possible if one is willing to ignore the order in which the officials are to mark their ratings. This is NOT a solution to the problem in the midterm (since it ignores both upwards and downwards order). In this case, all ratings are marked concurrently and the spinning in the first phase is done by the thread corresponding to the top official. In the second phase, each thread copies the final rating concurrently. If your answer is like this, you get 5 points. int initialRating[K]; int finalRating[K]; Threads *officials[K]; void main() { for (i = 0; i < K; i++) { initRating[i] = -1; finalRating[i] = -1; officials[i] = new Thread(); officials[i]->fork(simOfficial, i); } /* this is no longer needed as we don't need to enforce a * particular order */ /* initRating[0] = 0; */ waitForAllThreadsToComplete(); } void simOfficial(int id) { /* wait for the next lower official to mark her rating */ /* this is no longer needed as we don't need to enforce a * particular order */ /* while (initRating[id] == -1); currentThread->yield(); */ /* compute my rating - using a random value between 1 and 10 */ myRating = 1 + rand()%10; /* I set my rating concurrently with everyone else */ initRating[id] = myRating; if (id == K-1) { /* if I am the final official, I add up everyone's ratings * and add my own; and set my finalRating cell */ for (sum = myRating, i = 0; i < K-1; i++) { /* need to wait for a valid rating */ while (initRating[i] == -1) currentThread->yield(); sum += initRating[i]; } finalRating[id] = sum; } else { /* wait for the top official to compute the final rating */ while (finalRating[K-1] == -1) currentThread->yield(); finalRating[id] = finalRating[K-1]; } }