























Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
This document delves into the intricacies of operating systems, focusing on process management and concurrency. It explores concepts like process states, process creation, and the challenges of managing a growing number of processes. The document also examines concurrency, mutual exclusion, and synchronization, illustrating these concepts with practical examples and code snippets. It further analyzes different scheduling algorithms, including shortest remaining time, non-preemptive priority, and round robin, comparing their performance and efficiency.
Typology: Schemes and Mind Maps
1 / 31
This page cannot be seen from the preview
Don't miss anything!
























1.3 EAT = .9 (10) + .1 [ .8 (10 + 100) + .2 (10 + 100 + 10000) ] = 220ns OR EAT = 10 + .1 (100) + .02 (10000) = 220ns 1.4 a. Since the targeted memory module (MM) becomes available for another transaction 600 ns after the initiation of each store operation, and there are 8 MMs, it is possible to initiate a store operation every 100 ns. Thus, the maximum number of stores that can be initiated in one second would be: 109 /10^2 = 10^7 words per second Strictly speaking, the last five stores that are initiated are not completed until sometime after the end of that second, so the maximum transfer rate is really 107 – 5 words per second. b. From the argument in part (a), it is clear that the maximum write rate will be essentially 10^7 words per second as long as a MM is free in time to avoid delaying the initiation of the next write. For clarity, let the module cycle time include the bus busy time as well as the internal processing time the MM needs. Thus in part (a), the module cycle time was 600 ns. Now, so long as the module cycle time is 800 ns or less, we can still achieve 10^7 words per second; after that, the maximum write rate will slowly drop off toward zero.
2.1 a. I/O-bound processes use little processor time; thus, the algorithm will favor I/O-bound processes. b. if CPU-bound process is denied access to the processor ==> the CPU-bound process won't use the processor in the recent past. ==> the CPU-bound process won't be permanently denied access. 2.2 a. The time required to execute a batch is M + (N × T), and the cost of using the processor for this amount of time and letting N users wait meanwhile is (M + (N × T)) × (S + (N × W)). The total cost of service time and waiting time per customer is C = (M + (N × T)) × (S + (N × W))/N The result follows by setting dC/dN = 0 b. $0.60/hour. 2.3 The countermeasure taken was to cancel any job request that had been waiting for more than one hour without being honored. 2.4 The problem was solved by postponing the execution of a job until all its tapes were mounted. 2.5 An effective solution is to keep a single copy of the most frequently used procedures for file manipulation, program input and editing permanently (or semi-permanently) in the internal store and thus enable user programs to call them directly. Otherwise, the system will spend a considerable amount of time multiple copies of utility programs for different users.
3.4 ==> exponential growth of processes occurs
5.1 Dispatcher 1 Get ptr to next process to execute Update pointer Execute process Dispatcher 2 Get ptr to next process to execute Update pointer Execute process Execute the above sequentially - no problem with consistency Now interleave the first instruction on both dispatchers. The processors will execute the same process and one process will be skipped. 5.2 Mutual exclusion: If all three processes try to access the resource concurrently, two processes will enter Spago's due to AND criteria (i.e., sign can only be ONE value at a time). A social disaster! 5.3 1. Provide mutual exclusion? There are two cases to consider: a. A process is inside the critical section and another tried to enter: Without loss of generality, assume Penelope is inside the critical section and Nicole tries to enter. Before entering the critical section Penelope sets her own flag to 1. When Nicole tries to enter the critical section she will see that Lope is up and will get caught in the while loop. Nicole will continue in the while loop until Penelope lowers her flag, which happens only at the end of the critical section b. Both are trying to enter simultaneously: In this situation, if both reach their respective while loop at the top, then the SIGN will ensure that only one of them passes through. The SIGN is alternating between the two of them, and is only modified at the exit of a critical section.
2. No Deadlock? Suppose both are trying to enter simultaneously. In this case if the first is trapped into the while loop, then the SIGN will make one of the two women lower her flag and go into a loop waiting for the SIGN to change (the inner while loop). The other woman whose turn is set by the SIGN will be able to get into Spago's. 3. No Starvation? Assume one is blocked inside the inner while loop, while the other is in the critical section In such a case, if the one inside the critical section tries to re- enter, she will be blocked because on exit of the critical section she sets the SIGN to point to the other. Therefore, the one that just got out of the critical section will be forced to wait for her own turn. So, bounded waiting is taken care of. 4. Progress? Suppose one of them is trying to enter with no competition: In such a case, the flag of the other is down, and thus she can enter. In summary, ALL requirements are SATISFIED
The first two are part of each teller record, the first three are part of each customer record. The others are global. Identify events We could approach these from either the teller point of view, or the customer point of view. The latter is preferable, as each customer transaction is unique, while teller transactions are not. Hence we will not have to worry about synchronizing with the wrong event. —A customer arrives in the bank and joins a queue —A customer is called to the teller —A customer arrives at a teller window —A customer completes a transaction and leaves the bank We create a semaphore for each of these (except the first: that is assumed to be outside our control), as part of each customer record. Write customer process We write this first, since the customer is the driving process for the tellers. The customer process is characterized by a) the type of customer (normal or quick), and b) the number of the customer class customer(Thread): def init(self,quick,number): self.quick=quick; self.number=number self.tn = 0 self.call=semaphore() self.customer_arrive=semaphore() self.transaction_complete=semaphore() def isQuick(self): return self.quick def run(self): self.call.wait() # wait for our turn goto_teller(self.tn) # teller number tn is our teller elf.customer_arrive.signal() # tell teller we're here do_transaction() self.transaction_complete.signal() # tell teller we're
leave_bank Write teller process The teller process is characterized by a) the type of teller (normal or quick), and b) the number of the teller class teller(Thread): def run(self,quick,number): global mutexQ,c,Qserve,Nserve while (1): mutexQ.wait() if quick: while Qserve < j and not c[Qserve].isQuick: Qserve=Qserve+ if not c[Qserve].isQuick: Nserve=Nserve+1; Serving = Nserve else: Serving = Qserve else: while Nserve < j and c[Nserve].isQuick: Nserve=Nserve+ if c[Nserve].isQuick: Qserve=Qserve+1; Serving = Qserve
else: Serving = Nserve mutexQ.signal()
c[Serving].tn = number # flag our number c[Serving].call.signal() # tell the customer c[Serving].customer_arrive.wait() # wait for her c[Serving].transaction_complete.wait() # and her transaction The if quick: ... statement does all the queue calculations. We scan forward on the list of customers, looking for customers of our type. If we find one, that is the next customer to be served. If there are none, then the next customer in the opposite type of queue is to be served. Since this is updating shared variables, it must be a mutual exclusion zone. write bank process (This is really the main program.) Qserve = 0 # customer number for quick service Q Nserve = 0 # customer number for normal service Q t = n*[0] # list of tellers for i in range(1,n): # create and start all tellers if i < k: t[i] = teller(1,i) # create quick service teller else: t[i] = teller(0,i) # create normal service teller t[j].start() # start teller j = 0 # customer number c = [] # customer list while 1: # create and start customers forever j = j+ x = random() if x < QuickRatio: # QuickRatio is fraction of customers
c.append(customer(1,j)) # create a quick service customer else: c.append(customer(0,j)) # create a normal service customer c[j].start() # start customer
wait_random_interval() # for next customer to arrive Add critical sections There is only one: the queue computation to see who is next to be served. Identified above by the mutexQ variable. 5.7 The code for the one-writer many readers is fine if we assume that the readers have always priority. The problem is that the readers can starve the writer(s) since they may never all leave the critical region, i.e., there is always at least one reader in the critical region, hence the ‘wrt’ semaphore may never be signaled to writers and the writer process does not get access to ‘wrt’ semaphore and writes into the critical region. 5.8 a. For "x is 10", the interleaving producing the required behavior is easy to find since it requires only an interleaving at the source language statement level. The essential fact here is that the test for the value of x is interleaved with the increment of x by the other process. Thus, x was not equal to 10 when the test
5.9 Here the solution is simple: enclose the operations on the shared variable within semaphore operations, which will ensure that only one process will operate on x at a time. The only trick here is to realize that we have to enclose the if statement as well since if we do not, erroneous printing can still happen if one process is in the middle of the critical section while another is testing x. s: semaphore; parbegin P1: { shared int x; x = 10; for (; ;) { semWait(s); x = x - 1; x = x + 1; if (x != 10) printf("x is %d", x); semSignal(s); } } P2: { shared int x; x = 10; for (; ;) { semWait(s); x = x - 1; x = x + 1; if(x != 10) printf("x is %d", x); semSignal(s); } } parend
5.10 Here the essential point is that without an atomic operation to test and set the semaphore variable, the only way to ensure that the semaphore manipulations will not be interrupted and thus potentially corrupted, is to create a system call which blocks all interrupts. That way, after the spl(highest) we know that nothing will interrupt execution until the priority is set back to the previous value. The sleep and wakeup calls are used to avoid busy waiting in the kernel. A busy waiting solution was declared acceptable since the point of the question was to use spl as the way to ensure atomicity. However, if used, it will not actually work, because the machine will be trapped in an uninterruptible loop waiting for the semaphore to be released. Note that key(s) is meant to symbolize creating a unique integer to represent the semaphore in question. semWait(s, val) int old; while (1) { old = spl(highest); if ( s < val ) { spl(old); /* we could busy wait here, but would block the kernel */ sleep(key(s)); continue; } else { s = s - val; spl(old); } } semSignal(s, val) int old; old = spl(highest); s = s + val; spl(old); wakeup(key(s)); 5.11 To move the statement inside the critical section, but as late as possible, the statement would occur immediately after n--. But at this point, n = 0, therefore, consumer will not wait on semaphore delay. This means that consumer will not issue semSignalB(s). Therefore, n remains at 1. The producer therefore cannot issues a semSignalB(delay) and can get hung up at its statement semWaitB(s). Thus, both processes are waiting and deadlocked.
d. ANSWER is NO for the following reasons: IF this request were granted, then the new allocation matrix would be: allocation process A B C D P0 2 0 2 1 P1 0 1 1 1 P2 4 1 0 2 P3 1 0 0 1 P4 1 1 0 0 P5 4 2 4 4 Then the new need matrix would be allocation process A B C D P0 7 5 3 4 P1 2 1 2 2 P2 3 4 4 2 P3 2 3 3 1 P4 4 1 2 1 P5 0 2 0 0 And Available is then: Available A B C D 3 1 2 1 Which means I could NOT satisfy ANY process’ need. 6.4 a. Concurrency ratings In order from most-concurrent to least, here is a rough partial order on the deadlock-handling algorithms:
1. detect deadlock and kill thread, releasing its resources; detect deadlock and roll back thread's actions ; restart thread and release all resources if thread needs to wait. None of these algorithms limit concurrency before deadlock occurs, since they rely on runtime checks rather than static restrictions. Their effects after deadlock is detected are harder to characterize: they still allow lots of concurrency (in some cases they enhance it), but the computation may no longer be sensible or efficient. The third algorithm is the strangest, since so much of its concurrency will be useless repetition; because threads compete for execution time, this algorithm also prevents useful computation from advancing. Hence it is listed twice in this ordering, at both extremes. 2. banker's algorithm; resource ordering. These algorithms cause more unnecessary waiting than the previous two by restricting the range of allowable computations. The banker's algorithm prevents unsafe allocations (a proper superset of deadlock-producing allocations) and resource ordering restricts allocation sequences so that threads have fewer options as to whether they must wait or not.
3. reserve all resources in advance. This algorithm allows less concurrency than the previous two, but is less pathological than the worst one. By reserving all resources in advance, threads have to wait longer and are more likely to block other threads while they work, so the system-wide execution is in effect more linear. 4. restart thread and release all resources if thread needs to wait. As noted above, this algorithm has the dubious distinction of allowing both the most and the least amount of concurrency, depending on the definition of concurrency. b. Efficiency ratings. In order from most efficient to least, here is a rough partial order on the deadlock-handling algorithms: 1. reserve all resources in advance; resource ordering. These algorithms are most efficient because they involve no runtime overhead. Notice that this is a result of the same static restrictions that made these rank poorly in concurrency. 2. banker's algorithm; detect deadlock and kill thread, releasing its resources. These algorithms involve runtime checks on allocations which are roughly equivalent; the banker's algorithm performs a search to verify safety which is O(n m) in the number of threads and allocations, and deadlock detection performs a cycle-detection search which is O(n) in the length of resource- dependency chains. Resource-dependency chains are bounded by the number of threads, the number of resources, and the number of allocations. 3. detect deadlock and roll back thread's actions. This algorithm performs the same runtime check discussed previously but also entails a logging cost which is O(n) in the total number of memory writes performed. 4. restart thread and release all resources if thread needs to wait. This algorithm is grossly inefficient for two reasons. First, because threads run the risk of restarting, they have a low probability of completing. Second, they are competing with other restarting threads for finite execution time, so the entire system advances towards completion slowly if at all. This ordering does not change when deadlock is more likely. The algorithms in the first group incur no additional runtime penalty because they statically disallow deadlock-producing execution. The second group incurs a minimal, bounded penalty when deadlock occurs. The algorithm in the third tier incurs the unrolling cost, which is O(n) in the number of memory writes performed between checkpoints. The status of the final algorithm is questionable because the algorithm does not allow deadlock to occur; it might be the case that unrolling becomes more expensive, but the behavior of this restart algorithm is so variable that accurate comparative analysis is nearly impossible. 6.5 a. Yes. If foo( ) executes semWait(S) and then bar( ) executes semWait(R) both processes will then block when each executes its next instruction. Since each will then be waiting for a semSignal( ) call from the other, neither will ever resume execution. b. No. If either process blocks on a semWait( ) call then either the other process will also block as described in (a) or the other process is executing in its critical section. In the latter case, when the running process leaves its critical section, it will execute a semSignal( ) call, which will awaken the blocked process.
P3 3K (a) (b) (c) (d) P4 cannot be allocated P2 4K not allocated 4K not allocated 5K P3 6K P3 3K P 2 4K not allocated 1K not allocated 2K P3 4K (3K used) P 4 8K (6K used) P2 4 K P3 4 K (3K used) P2 4 K P4 (the other part) 2 K P4 (one part) 2 K not allocated 2K 7.7 12 bits 7.8 64 bits
8.1 (d) The system is obviously thrashing. You do not want to increase the number of processes competing for page frames. Installing a faster processor will not help; processor is underutilized as is. There is no indication that the current paging disk is inadequate. (A faster paging disk might be helpful.) 8.2 (e) Processes being unable to establish their working set of pages. A local page replacement algorithm may increase the probability of one process thrashing, but cannot be considered the cause of it. If a FIFO page replacement algorithm is ineffective, it will increase the probability of page thrashing, but (e) is the best answer. 8.3 a. 200 nsec + 200 nsec = 400 nsec b. 75 (10 nsec + 200 nsec) + .25 (10 nsec + 200 nsec + 200 nsec) = about 250 nsec TLB page table page c. Add 0.7 (10 nsec + 200 nsec) + 0.2 (200 nsec + 200 nsec)