Processes & Threads Flashcards
In Fig. 2-2 (https://imgur.com/a/TlMWLhF), three process states are shown. In theory, with three states, there could be six
transitions, two out of each state. However, only four transitions are shown. Are there any
circumstances in which either or both of the missing transitions might occur?
(TUT4)
The transition from blocked to running is conceivable. Suppose that a process is blocked on I/O
and the I/O finishes. If the CPU is otherwise idle, the process could go directly from blocked to
running. The other missing transition, from ready to blocked, is impossible. A ready process
cannot do I/O or anything else that might block it. Only a running process can block.
Suppose that you were to design an advanced computer architecture that did process
switching in hardware, instead of having interrupts. What information would the CPU need?
Describe how the hardware process switching might work.
You could have a register containing a pointer to the current process-table entry. When I/O
completed, the CPU would store the current machine state in the current process-table entry.
Then it would go to the interrupt vector for the interrupting device and fetch a pointer to
another process-table entry (the service procedure). This process would then be started up.
On all current computers, at least part of the interrupt handlers are written in assembly
language. Why?
Generally, high-level languages do not allow the kind of access to CPU hardware that is
required. For instance, an interrupt handler may be required to enable and disable the interrupt
servicing a particular device, or to manipulate data within a process’ stack area. Also, interrupt
service routines must execute as rapidly as possible.
When an interrupt or a system call transfers control to the operating system, a kernel stack
area separate from the stack of the interrupted process is generally used. Why?
(TUT4)
The separate stack area is used for the interrupted processes. The causes for using the distinct
stack for kernel are as given below:
● By using distinct stack, the data is not overwritten on the kernel;
● By doing so, the operating system will not crash;
● To protect the information of processes from malicious users;
● The separate memory space can be used to make system calls.
A computer system has enough room to hold five programs in its main memory. These
programs are idle waiting for I/O half the time. What fraction of the CPU time is wasted?
CPU utilization = 1 – pⁿ CPU time wasted = pⁿ Number of programs: n = 5 Waiting for I/O: p = 50% = 0.5 = 1/2 CPU time wasted = (1/2)⁵ = 1/32
A computer has 4 GB of RAM of which the operating system occupies 512 MB. The
processes are all 256 MB (for simplicity) and have the same characteristics. If the goal is 99%
CPU utilization, what is the maximum I/O wait that can be tolerated?
There is enough room for 14 processes in memory: (4 GB – 512 MB) / 256 MB = 14
Now we have equation: 0.99 = 1 – p¹⁴ => p¹⁴ = 0. 01 => p = 0.72
Answer: We can tolerate processes with up to 72% I/O wait.
Multiple jobs can run in parallel and finish faster than if they had run sequentially. Suppose
that two jobs, each needing 20 minutes of CPU time, start simultaneously. How long will the
last one take to complete if they run sequentially? How long if they run in parallel? Assume
50% I/O wait.
(FE17)
If each job has 50% I/O wait, then it will take 40 minutes to complete in the absence of
competition. If run sequentially, the second one will finish 80 minutes after the first one starts.
With two jobs, the approximate CPU utilization is 1 − 0.5² = 0.75. Thus, each one gets 0.375 CPU
minute per minute of real time. To accumulate 20 minutes of CPU time, a job must run for
20/0.375 minutes, or about 53.33 minutes.
Thus running sequentially the jobs finish after 80 minutes, but running in parallel they finish
after 53.33 minutes.
Consider a multiprogrammed system with degree of 6 (i.e., six programs in memory at the
same time). Assume that each process spends 40% of its time waiting for I/O. What will be the
CPU utilization?
(FFE18) (TUT4) (TUT5)
The probability that all processes are waiting for I/O is 0.4⁶ which is 0.004096. Therefore, CPU
utilization is 1 − 0.004096 = 0.995904 = 99%.
Assume that you are trying to download a large 2-GB file from the Internet. The file is
available from a set of mirror servers, each of which can deliver a subset of the file’s bytes;
assume that a given request specifies the starting and ending bytes of the file. Explain how
you might use threads to improve the download time.
The client process can create separate threads; each thread can fetch a different part of the file
from one of the mirror servers. This can help reduce downtime. Of course, there is a single
network link being shared by all threads. This link can become a bottleneck as the number of
threads becomes very large.
In the text it was stated that the model of Fig. 2-11(a) (https://imgur.com/a/npnSXA6) was not suited to a file server using
a cache in memory. Why not? Could each process have its own cache?
It would be difficult, if not impossible, to keep the file system consistent. Suppose that a client
process sends a request to server process 1 to update a file. This process updates the cache
entry in its memory. Shortly thereafter, another client process sends a request to server 2 to
read that file. Unfortunately, if the file is also cached there, server 2, in its innocence, will return
obsolete data. If the first process writes the file through to the disk after caching it, and server 2
checks the disk on every read to see if its cached copy is up-to-date, the system can be made to
work, but it is precisely all these disk accesses that the caching system is trying to avoid.
If a multithreaded process forks, a problem occurs if the child gets copies of all the
parent’s threads. Suppose that one of the original threads was waiting for keyboard input.
Now two threads are waiting for keyboard input, one in each process. Does this problem ever
occur in single-threaded processes?
(TUT4) (TUT5)
A single-threaded process cannot fork if it is waiting for a keyboard input as it would remain in
waiting state until it receives the input from the keyboard. Once it receives the input, it would
resume its execution.
In a multithreaded process, as two processes are waiting for a keyboard input, only one of them
can resume execution once the keyboard input is received and the other would always stay
suspended. Thus, the problem of two threads waiting for an input will occur in a multithreaded
process.
In Fig. 2-8 (https://imgur.com/a/vDmpDVe), a multithreaded Web server is shown. If the only way to read from a file is the
normal blocking read system call, do you think user-level threads or kernel-level threads are
being used for the Web server? Why?
A worker thread will block when it has to read a Web page from the disk. If user-level threads
are being used, this action will block the entire process, destroying the value of multithreading.
Thus it is essential that kernel threads are used to permit some threads to block without
affecting the others.
In the text, we described a multithreaded Web server, showing why it is better than a
single-threaded server and a finite-state machine server. Are there any circumstances in
which a single-threaded server might be better? Give an example.
Yes. If the server is entirely CPU bound, there is no need to have multiple threads. It just adds
unnecessary complexity. As an example, consider a telephone directory assistance number (like
555-1212) for an area with 1 million people. If each (name, telephone number) record is, say, 64
characters, the entire database takes 64 megabytes and can easily be kept in the server’s
memory to provide fast lookup.
…the register set is listed as a per-thread rather than a per-process item. Why?
After all, the machine has only one set of registers.
The register is called a per-thread item because the context saved in a register is thread-specific
information. The register stores the state of every thread so that it can be used during context
switching – these data are saved and reloaded on the next execution.
Why would a thread ever voluntarily give up the CPU by calling thread yield? After all,
since there is no periodic clock interrupt, it may never get the CPU back.
Threads in a process cooperate. They are not hostile to one another. If yielding is needed for the
good of the application, then a thread will yield. After all, it is usually the same programmer
who writes the code for all of them.
Can a thread ever be preempted by a clock interrupt? If so, under what circumstances? If
not, why not?
User-level threads cannot be preempted by the clock unless the whole process’ quantum has
been used up (although transparent clock interrupts can happen). Kernel-level threads can be
preempted individually. In the latter case, if a thread runs too long, the clock will interrupt the
current process and thus the current thread. The kernel is free to pick a different thread from
the same process to run next if it so desires.
In this problem you are to compare reading a file using a single-threaded file server and a
multithreaded server. It takes 12 msec to get a request for work, dispatch it, and do the rest
of the necessary processing, assuming that the data needed are in the block cache. If a disk
operation is needed, as is the case one-third of the time, an additional 75 msec is required,
during which time the thread sleeps. How many requests/sec can the server handle if it is
single-threaded? If it is multithreaded?
(FFE18)
In the single-threaded case, the cache hits take 12 msec and cache misses take 87 msec. The
weighted average is 2/3 × 12 + 1/3 × 87 = 37 msec. Thus, the mean request takes 37 msec and
the server can do about 1000 / 37 = 27 per second. For a multithreaded server, all the waiting
for the disk is overlapped, so every request takes 12 msec, and the server can handle 1000 / 12
= 83 requests per second.
What is the biggest advantage of implementing threads in user space? What is the biggest
disadvantage?
The biggest advantage is the efficiency. No traps to the kernel are needed to switch threads. The
biggest disadvantage is that if one thread blocks, the entire process blocks.
In Fig. 2-15 (https://imgur.com/a/CkNgCLR) the thread creations and messages printed by the threads are interleaved at
random. Is there a way to force the order to be strictly thread 1 created, thread 1 prints
message, thread 1 exits, thread 2 created, thread 2 prints message, thread 2 exists, and so on?
If so, how? If not, why not?
Yes, it can be done. After each call to pthread_create, the main program could do a pthread_join
to wait until the thread just created has exited before creating the next thread.
In the discussion on global variables in threads, we used a procedure create_global to allocate storage for a pointer to the variable, rather than the variable itself. Is this essential, or could the procedures work with the values themselves just as well?
The pointers are really necessary because the size of the global variable is unknown. It could be
anything from a character to an array of floating-point numbers. If the value were stored, one
would have to give the size to create_global, which is all right, but what type should the second
parameter of set_global be, and what type should the value of read_global be?
Consider a system in which threads are implemented entirely in user space, with the run-
time system getting a clock interrupt once a second. Suppose that a clock interrupt occurs
while some thread is executing in the run-time system. What problem might occur? Can you
suggest a way to solve it?
It could happen that the runtime system is precisely at the point of blocking or unblocking a
thread, and is busy manipulating the scheduling queues. This would be a very inopportune
moment for the clock interrupt handler to begin inspecting those queues to see if it was time to
do thread switching, since they might be in an inconsistent state. One solution is to set a flag
when the runtime system is entered. The clock handler would see this and set its own flag, then
return. When the runtime system finished, it would check the clock flag, see that a clock
interrupt occurred, and now run the clock handler.
Suppose that an operating system does not have anything like the select system call to see
in advance if it is safe to read from a file, pipe, or device, but it does allow alarm clocks to be
set that interrupt blocked system calls. Is it possible to implement a threads package in user
space under these conditions? Discuss.
Yes it is possible, but inefficient. A thread wanting to do a system call first sets an alarm timer,
then does the call. If the call blocks, the timer returns control to the threads package. Of course,
most of the time the call will not block, and the timer has to be cleared. Thus each system call
that might block has to be executed as three system calls. If timers go off prematurely, all kinds
of problems develop. This is not an attractive way to build a threads package.