Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 5 Synchronization

Similar presentations


Presentation on theme: "Chapter 5 Synchronization"— Presentation transcript:

1 Chapter 5 Synchronization

2 Overview A cooperating process can affect or be affected by other processes in the system Cooperating processes can either directly share a logical address space i.e., Both code and data Achieved through the use of threads Or be allowed to share data only through files or messages Concurrent access to shared data may result in data inconsistency Ensure the orderly execution of cooperating processes that share a logical address space Data consistency is maintained 1.1 CLOUD COMPUTING IN A NUTSHELL

3 Background The CPU scheduler switches rapidly between processes
To provide concurrent execution One process may only partially complete execution before another process is scheduled A process may be interrupted at any point in its instruction stream The processing core may be assigned to execute instructions of another process Concurrent execution can contribute to issues Involving the integrity of data shared by several processes The producer-consumer problem 1.1 CLOUD COMPUTING IN A NUTSHELL

4 Background (cont.) The code for the producer process
Representative of operating systems A bounded buffer could be used to enable processes to share memory To modify the algorithm to remedy the deficiency Allowing at most BUFFER_SIZE - 1 items in the buffer at the same time One method is to add an integer variable counter Initialized to 0 Incremented every time a new item is added to the buffer Decremented every time one item is removed from the buffer The code for the producer process 1.1 CLOUD COMPUTING IN A NUTSHELL

5 Background (cont.) The code for the consumer process
1.1 CLOUD COMPUTING IN A NUTSHELL

6 Background (cont.) The producer and consumer routines shown above are correct separately May not function correctly when executed concurrently Suppose that the value of the variable counter is currently 5 If the producer and consumer processes concurrently execute the statements counter++ and counter-- Following the execution of these two statements, the value of the variable counter may be 4, 5, or 6 The only correct result is counter == 5, which is generated correctly if the producer and consumer execute separately 1.1 CLOUD COMPUTING IN A NUTSHELL

7 Background (cont.) How the value of counter may be incorrect
The statement counter++ may be implemented in machine language on a typical machine register1 is one of the local CPU registers The statement “counter--” is implemented as register2 is one of the local CPU registers register1 and register2 may be the same physical register, e.g., an accumulator Remember that the contents of this register will be saved and restored by the interrupt handler 1.1 CLOUD COMPUTING IN A NUTSHELL

8 Background (cont.) One such interleaving is the following
The concurrent execution of counter++ and counter-- is equivalent to a sequential execution The above lower-level statements are interleaved in some arbitrary order The order within the high-level statement is preserved One such interleaving is the following Arrived at the incorrect state counter == 4, indicating that four buffers are full In fact, five buffers are full If reversing the order of the statements at T4 and T5, arrive at the incorrect state counter == 6 1.1 CLOUD COMPUTING IN A NUTSHELL

9 Background (cont.) Arrive at this incorrect state Both processes are allowed to manipulate the variable counter concurrently If several processes access and manipulate the same data concurrently The outcome of the execution depends on the particular order in which the access takes place Called a race condition Need to ensure that only one process at a time can be manipulating the variable counter Require that the processes be synchronized in some way Occur frequently in OSes different parts of the system manipulate resources 1.1 CLOUD COMPUTING IN A NUTSHELL

10 Background (cont.) In multithreaded applications
Several threads are quite possibly sharing data Any changes that result from such activities do not to interfere with one another Need process synchronization and coordination among cooperating processes 1.1 CLOUD COMPUTING IN A NUTSHELL

11 The Critical-Section Problem
A system consisting of n processes {P0, P1, ..., Pn−1} Each process has a segment of code, called a critical section Therein the process may be changing common variables, updating a table, writing a file, and so on When a process is executing in its critical section No other process is allowed to execute in its critical section No two processes are executing in their critical sections at the same time The critical-section problem is to design a protocol that the processes can use to cooperate 1.1 CLOUD COMPUTING IN A NUTSHELL

12 The Critical-Section Problem (cont.)
Each process must request permission to enter its critical section The section of code implementing this request is the entry section May be followed by an exit section The remaining code is the remainder section The general structure of a critical section 1.1 CLOUD COMPUTING IN A NUTSHELL

13 The Critical-Section Problem (cont.)
The critical-section problem must satisfy three requirements Mutual exclusion If process Pi is executing in its critical section, no other processes can be executing in their critical sections Progress Only those processes that are not executing in their remainder sections can participate in deciding which will enter its critical section next This selection cannot be postponed indefinitely Bounded waiting There exists a bound on the number of times that other processes are allowed to enter their critical sections 1.1 CLOUD COMPUTING IN A NUTSHELL

14 The Critical-Section Problem (cont.)
After a process has made a request to enter its critical section and before that request is granted Each process is assumed to be executing at a nonzero speed No assumption concerning the relative speed of the n processes Many kernel-mode processes may be active in the operating system The code implementing an OS (kernel code) is subject to several possible race conditions Consider a kernel data structure that maintains a list of all open files in the system Must be modified when a new file is opened or closed 1.1 CLOUD COMPUTING IN A NUTSHELL

15 The Critical-Section Problem (cont.)
Adding the file to the list or removing it from the list If two processes are to open files simultaneously, the separate updates to this list results in a race condition Other kernel data structures that are prone to possible race conditions Structures for maintaining memory allocation, for maintaining process lists, and for interrupt handling Kernel developers ensure that the operating system is free from such race conditions Two general approaches are used to handle critical sections in operating systems Preemptive kernels and nonpreemptive kernels A preemptive kernel allows a process to be preempted while it is running in kernel mode 1.1 CLOUD COMPUTING IN A NUTSHELL

16 The Critical-Section Problem (cont.)
A nonpreemptive kernel does not allow a process running in kernel mode to be preempted A kernel-mode process will run until it exits kernel mode, blocks, or voluntarily yields control of the CPU A nonpreemptive kernel is essentially free from race conditions on kernel data structures Only one process is active in the kernel at a time Preemptive kernels must be carefully designed Ensuring that shared kernel data are free from race conditions A preemptive kernel is more responsive Less risk that a kernel-mode process will run for an arbitrarily long period Before relinquishing the CPU to waiting processes 1.1 CLOUD COMPUTING IN A NUTSHELL

17 The Critical-Section Problem (cont.)
This risk can also be minimized by designing kernel code that does not behave in this way A preemptive kernel is more suitable for real-time programming Allow a real-time process to preempt a process currently running in the kernel Discuss how various operating systems manage preemption within the kernel 1.1 CLOUD COMPUTING IN A NUTSHELL

18 Synchronization Hardware
Software-based solutions are not guaranteed to work on modern computers Several more solutions to the critical-section problem using techniques Ranging from hardware to software-based APIs available to both kernel developers and application programmers All these are based on the premise of locking Protecting critical regions through the use of locks The designs of such locks can be quite sophisticated Some simple hardware instructions are available on many systems 1.1 CLOUD COMPUTING IN A NUTSHELL

19 Synchronization Hardware (cont.)
Can be used effectively in solving the critical-section problem Hardware features can make any programming task easier and improve system efficiency The critical-section problem can be solved simply in a single-processor environment Preventing interrupts from occurring while a shared variable was being modified The current sequence of instructions will be allowed to execute in order without preemption No other instructions will be run No unexpected modifications can be made to the shared variable 1.1 CLOUD COMPUTING IN A NUTSHELL

20 Synchronization Hardware (cont.)
Often the approach taken by nonpreemptive kernels Disabling interrupts on a multiprocessor can be time consuming The message is passed to all the processors This delays entry into each critical section System efficiency decreases Also consider the effect on a system’s clock The clock is kept updated by interrupts Many modern computer systems provide special hardware instructions Allow us either to test and modify the content of a word atomically 1.1 CLOUD COMPUTING IN A NUTSHELL

21 Synchronization Hardware (cont.)
Or to swap the contents of two words atomically As one uninterruptible unit Use these special instructions to solve the critical-section problem in a relatively simple way Abstract the main concepts behind these types of instructions By describing the test_and_set() and compare_and_swap() instructions The test_and_set() instruction 1.1 CLOUD COMPUTING IN A NUTSHELL

22 Synchronization Hardware (cont.)
Executed atomically If two test_and_set() instructions are executed simultaneously, i.e., each on a different CPU Will be executed sequentially in some arbitrary order If test_and_set() is supported Can implement mutual exclusion by declaring a boolean variable lock Initialized to false The structure of process Pi 1.1 CLOUD COMPUTING IN A NUTSHELL

23 Synchronization Hardware (cont.)
The compare_and_swap() instruction operates on three operands The operand value is set to new_value Only if the expression (*value == exected) is true compare_and_swap() always returns the original value of the variable value compare_and_swap() is executed atomically 1.1 CLOUD COMPUTING IN A NUTSHELL

24 Synchronization Hardware (cont.)
Mutual exclusion can be provided as A global variable lock is declared and is initialized to 0 The first process invokes compare_and_swap() Set lock to 1 It will then enter its critical section The original value of lock was equal to the expected value of 0 Subsequent calls to compare_and_swap() will not succeed lock now is not equal to the expected value of 0 When a process exits its critical section Sets lock back to 0, which allows another process to enter its critical section 1.1 CLOUD COMPUTING IN A NUTSHELL

25 Synchronization Hardware (cont.)
The structure of process Pi The above algorithms satisfy the mutual-exclusion requirement Do not satisfy the bounded-waiting requirement 1.1 CLOUD COMPUTING IN A NUTSHELL

26 Synchronization Hardware (cont.)
Another algorithm using the test_and_set() instruction Satisfies all the critical-section requirements The common data structures These data structures are initialized to false The mutual exclusion requirement is met Process Pi can enter its critical section only if either waiting[i] == false or key == false The value of key can become false only if the test_and_set() is executed The first process to execute the test_and_set() will find lock == false 1.1 CLOUD COMPUTING IN A NUTSHELL

27 Synchronization Hardware (cont.)
All others must wait The variable waiting[i] can become false only if another process leaves its critical section Only one waiting[i] is set to false, maintaining the mutual-exclusion requirement The progress requirement is me A process exiting the critical section either sets lock to false or sets waiting[j] to false Both allow a process that is waiting to enter its critical section to proceed The bounded-waiting requirement is met As a process leaves its critical section, scans the array waiting in the ordering (i+1, i+2, ..., n−1, 0, ..., i−1) Designates the first process in this ordering that is in the entry section (waiting[j] == true) as the next one to enter the critical section 1.1 CLOUD COMPUTING IN A NUTSHELL

28 Synchronization Hardware (cont.)
Any process waiting to enter its critical section will thus do so within n−1 turns 1.1 CLOUD COMPUTING IN A NUTSHELL

29 Mutex Locks The hardware-based solutions to the critical-section problem are complicated Generally inaccessible to application programmers Operating-systems designers build software tools to solve the critical-section problem The simplest of these tools is the mutex lock The term mutex is short for mutual exclusion Use the mutex lock to protect critical regions and thus prevent race conditions A process must acquire the lock before entering a critical section Releases the lock when it exits the critical section 1.1 CLOUD COMPUTING IN A NUTSHELL

30 Mutex Locks (cont.) A mutex lock has a boolean variable available
The acquire() function acquires the lock The release() function releases the lock A mutex lock has a boolean variable available Indicates if the lock is available or not If the lock is available A call to acquire() succeeds The lock is then considered unavailable A process that attempts to acquire an unavailable lock Blocked until the lock is released 1.1 CLOUD COMPUTING IN A NUTSHELL

31 Mutex Locks (cont.) The definition of acquire()
The definition of release() Calls to either acquire() or release() must be performed atomically Mutex locks are often implemented using one of the hardware mechanisms 1.1 CLOUD COMPUTING IN A NUTSHELL

32 Mutex Locks (cont.) The disadvantage of the implementation is that it requires busy waiting While a process is in its critical section Any other process that tries to enter its critical section must loop continuously in the call to acquire() This type of mutex lock is also called a spinlock The process spins while waiting for the lock to become available The same issue with the test_and_set() instruction and the compare_and_swap() instruction This continual looping is clearly a problem in a real multiprogramming system A single CPU is shared among many processes 1.1 CLOUD COMPUTING IN A NUTSHELL

33 Mutex Locks (cont.) Spinlocks do have an advantage
Busy waiting wastes CPU cycles Some other process might be able to use productively Spinlocks do have an advantage No context switch is required when a process must wait on a lock A context switch may take considerable time When locks are expected to be held for short times, spinlocks are useful 1.1 CLOUD COMPUTING IN A NUTSHELL

34 Semaphores Mutex locks are generally considered the simplest of synchronization tools A semaphore is a more robust tool that can behave similarly to a mutex lock Can also provide more sophisticated ways for processes to synchronize their activities A semaphore S is an integer variable Apart from initialization, accessed only through two standard atomic operations: wait() and signal() The wait() operation was originally termed P, from the Dutch proberen, to test signal() was originally called V, from verhogen, to increment 1.1 CLOUD COMPUTING IN A NUTSHELL

35 Semaphores (cont.) The definition of wait() The definition of signal()
All modifications to the integer value of the semaphore must be executed indivisibly 1.1 CLOUD COMPUTING IN A NUTSHELL

36 Semaphores (cont.) In the case of wait(S)
When one process modifies the semaphore value, no other process can simultaneously modify that same semaphore value In the case of wait(S) The testing of the integer value of S (S ≤ 0) and its possible modification (S--) must be executed without interruption 1.1 CLOUD COMPUTING IN A NUTSHELL

37 Semaphore Usage Operating systems often distinguish between counting and binary semaphores The value of a counting semaphore can range over an unrestricted domain The value of a binary semaphore can range only between 0 and 1 Binary semaphores behave similarly to mutex locks On systems that do not provide mutex locks, binary semaphores can be used instead for mutual exclusion Counting semaphores can be used to control access to a given resource Consisting of a finite number of instances 1.1 CLOUD COMPUTING IN A NUTSHELL

38 Semaphore Usage (cont.)
The semaphore is initialized to the number of resources available Each process that wishes to use a resource performs a wait() operation on the semaphore Decrementing the count When a process releases a resource, it performs a signal() operation Incrementing the count When the count for the semaphore goes to 0 All resources are being used Processes that wish to use a resource will block Until the count becomes greater than 0 1.1 CLOUD COMPUTING IN A NUTSHELL

39 Semaphore Usage (cont.)
Can also use semaphores to solve various synchronization problems Consider two concurrently running processes P1 with a statement S1 P2 with a statement S2 S2 must be executed only after S1 has completed Can implement this scheme readily by Letting P1 and P2 share a common semaphore synch, initialized to 0 In process P1, insert the statements 1.1 CLOUD COMPUTING IN A NUTSHELL

40 Semaphore Usage (cont.)
In process P2, insert the statements P2 will execute S2 only after P1 has invoked signal(synch) after statement S1 has been executed synch is initialized to 0 1.1 CLOUD COMPUTING IN A NUTSHELL

41 Semaphore Implementation
The implementation of mutex locks suffers from busy waiting The definitions of the wait() and signal() semaphore operations present the same problem To overcome the need for busy waiting, modify the definition of wait() and signal() As a process executes the wait() operation and finds that the semaphore value is not positive The process must wait Rather than engaging in busy waiting, the process can block itself The block operation places a process into a waiting queue associated with the semaphore 1.1 CLOUD COMPUTING IN A NUTSHELL

42 Semaphore Implementation (cont.)
The state of the process is switched to the waiting state Control is transferred to the CPU scheduler, which selects another process to execute As an other process executes a signal() operation A process that is blocked, waiting on a semaphore, should be restarted The process is restarted by a wakeup() operation Changes the process from the waiting state to the ready state The process is then placed in the ready queue The CPU may or may not be switched from the running process to the newly ready process Depending on the CPU-scheduling algorithm 1.1 CLOUD COMPUTING IN A NUTSHELL

43 Semaphore Implementation (cont.)
To implement semaphores under this definition, define a semaphore as Each semaphore has an integer value and a list of processes list When a process must wait() on a semaphore, it is added to the list of processes A signal() operation removes one process from the list of waiting processes and awakens that process The wait() operation can be defined as 1.1 CLOUD COMPUTING IN A NUTSHELL

44 Semaphore Implementation (cont.)
The signal() operation can be defined as 1.1 CLOUD COMPUTING IN A NUTSHELL

45 Semaphore Implementation (cont.)
The block() operation suspends the process that invokes it The wakeup(P) operation resumes the execution of a blocked process P These two operations are provided by the operating system as basic system calls In this implementation, semaphore values may be negative Semaphore values are never negative under the definition of semaphores with busy waiting If a semaphore value is negative Its magnitude is the number of waiting processes Results from switching the order of the decrement and the test in the implementation of the wait() operation 1.1 CLOUD COMPUTING IN A NUTSHELL

46 Semaphore Implementation (cont.)
The list of waiting processes Can be easily implemented by a link field in each process control block (PCB) Each semaphore contains an integer value and a pointer to a list of PCBs One way to add and remove processes from the list so as to ensure bounded waiting To use a FIFO queue The semaphore contains both head and tail pointers to the queue The list can use any queueing strategy Correct usage of semaphores does not depend on a particular queueing strategy for the semaphore lists 1.1 CLOUD COMPUTING IN A NUTSHELL

47 Semaphore Implementation (cont.)
Semaphore operations must be executed atomically No two processes can execute wait() and signal() on the same semaphore simultaneously This is a critical-section problem In a single-processor environment, can be solved simply inhibiting interrupts during the time the wait() and signal() operations are executing This scheme works in a single-processor environment Once interrupts are inhibited, instructions from different processes cannot be interleaved Only the currently running process executes until interrupts are reenabled The scheduler can regain control 1.1 CLOUD COMPUTING IN A NUTSHELL

48 Semaphore Implementation (cont.)
Not yet completely eliminate busy waiting with this above definition Move busy waiting from the entry section to the critical sections of application programs These sections are short, and if properly coded, they should be no more than about ten instructions The critical section is almost never occupied Busy waiting occurs rarely, for only a short time An entirely different situation exists Application programs whose critical sections may be long, minutes or even hours, or may almost always be occupied In such cases, busy waiting is extremely inefficient 1.1 CLOUD COMPUTING IN A NUTSHELL

49 Deadlocks and Starvation
The implementation of a semaphore with a waiting queue may result in a situation Two or more processes are waiting indefinitely for an event Caused only by one of the waiting processes The event in question is the execution of a signal() operation When such a state is reached These processes are said to be deadlocked Consider a system with two processes P0 and P1 Each accessing two semaphores, S and Q Set to the value 1 1.1 CLOUD COMPUTING IN A NUTSHELL

50 Deadlocks and Starvation (cont.)
P0 executes wait(S) and P1 executes wait(Q) When P0 executes wait(Q) It must wait until P1 executes signal(Q) When P1 executes wait(S) It must wait until P0 executes signal(S) These signal() operations cannot be executed P0 and P1 are deadlocked 1.1 CLOUD COMPUTING IN A NUTSHELL

51 Deadlocks and Starvation (cont.)
A set of processes is in a deadlocked state Every process is waiting for an event that can be caused only by another process in the same set The events mainly concerned here are resource acquisition and release Other types of events may result in deadlocks Another problem is indefinite blocking Or starvation A situation in which processes wait indefinitely with in the semaphore. May occur if we remove processes from the list associated with a semaphore in LIFO order Last-in, first-out 1.1 CLOUD COMPUTING IN A NUTSHELL

52 Priority Inversion A scheduling challenge arises
A higher-priority process needs to read or modify kernel data that are currently being accessed by a lower-priority process Or a chain of lower-priority processes Kernel data are typically protected with a lock The higher-priority process will have to wait for a lower-priority one to finish with the resource The situation becomes more complicated If the lower-priority process is preempted in favor of another process with a higher priority Consider three processes: L, M, and H Their priorities follow the order L < M < H 1.1 CLOUD COMPUTING IN A NUTSHELL

53 Priority Inversion (cont.)
Process H requires resource R Currently being accessed by process L Ordinarily, process H will wait for L to finish using resource R Now process M becomes runnable Thereby preempting process L Indirectly, a process with a lower priority, i.e. M, has affected how long process H must wait for L to relinquish resource R This problem is known as priority inversion Occurs only in systems with more than two priorities One solution is to have only two priorities Insufficient for most general-purpose OSes 1.1 CLOUD COMPUTING IN A NUTSHELL

54 Priority Inversion (cont.)
Solve the problem with a priority-inheritance protocol All processes accessing resources needed by a higher-priority process inherit the higher priority Until they are finished with the resources in question When they are finished, their priorities revert to their original values e.g., Such a protocol will allow process L to temporarily inherit the priority of process H Preventing process M from preempting its execution When process L had finished using resource R Relinquishes the inherited priority from H Resource R will now be available Process H, not M, will run next 1.1 CLOUD COMPUTING IN A NUTSHELL

55 Pthreads Synchronization
The above synchronization methods pertain to synchronization within the kernel The Pthreads API is available for programmers at the user level Not part of any particular kernel This API provides mutex locks, condition variables, and read-write locks For thread synchronization Mutex locks represent the fundamental synchronization technique for Pthreads Used to protect critical sections of code A thread acquires the lock before entering a critical section Releases it upon exiting the critical section 1.1 CLOUD COMPUTING IN A NUTSHELL

56 Pthreads Synchronization (cont.)
Pthreads uses the pthread_mutex_t data type for mutex locks A mutex is created with the pthread_mutex_init() function The first parameter is a pointer to the mutex By passing NULL as a second parameter, initialize the mutex to its default attributes The mutex is acquired and released with the pthread_mutex_lock() and pthread_mutex_unlock() functions 1.1 CLOUD COMPUTING IN A NUTSHELL

57 Pthreads Synchronization (cont.)
If the mutex lock is unavailable when pthread_mutex_lock() is invoked The calling thread is blocked until the owner invokes pthread_mutex_unlock() All mutex functions return a value of 0 with correct operation If an error occurs, return a nonzero error code The code for protecting a critical section with mutex locks 1.1 CLOUD COMPUTING IN A NUTSHELL

58 Pthreads Synchronization (cont.)
Condition variables and read-write locks behave similarly to the way Many systems that implement Pthreads also provide semaphores Not part of the Pthreads standard Belong to the POSIX SEM extension POSIX specifies two types of semaphores Named and unnamed A named semaphore has an actual name in the file system Can be shared by multiple unrelated processes Unnamed semaphores can be used only by threads belonging to the same process 1.1 CLOUD COMPUTING IN A NUTSHELL

59 Pthreads Synchronization (cont.)
The sem_init() function is for creating and initializing an unnamed semaphore A pointer to the semaphore A flag indicating the level of sharing The semaphore’s initial value By passing the flag 0 This semaphore can be shared only by threads belonging to the process that created the semaphore A nonzero value would allow other processes to access the semaphore as well 1.1 CLOUD COMPUTING IN A NUTSHELL

60 Pthreads Synchronization (cont.)
Initialize the semaphore to the value 1 The classical wait() and signal() semaphore operations Pthreads names these operations sem_wait() and sem_post(), respectively Protecting a critical section using the semaphore created above: 1.1 CLOUD COMPUTING IN A NUTSHELL

61 Pthreads Synchronization (cont.)
All semaphore functions return 0 when successful Nonzero when an error condition occurs There are other extensions to the Pthreads API Including spinlocks Not all extensions are considered portable from one implementation to another 1.1 CLOUD COMPUTING IN A NUTSHELL

62 The Bounded-Buffer Problem
A synchronization problem Use semaphores for synchronization The traditional way to present such solutions Actual implementations of these solutions can use mutex locks in place of binary semaphores The bounded-buffer problem Commonly used to illustrate the power of synchronization primitives Present a general structure of this scheme Without committing ourselves to any particular implementation The producer and consumer processes share the following data structures 1.1 CLOUD COMPUTING IN A NUTSHELL

63 The Bounded-Buffer Problem (cont.)
The pool consists of n buffers Each is capable of holding one item The mutex semaphore provides mutual exclusion for accesses to the buffer pool Initialized to the value 1 The empty and full semaphores count the number of empty and full buffers The semaphore empty is initialized to the value n The semaphore full is initialized to the value 0 The code for the producer process 1.1 CLOUD COMPUTING IN A NUTSHELL

64 The Bounded-Buffer Problem (cont.)
The producer producing full buffers for the consumer The code for the consumer process The symmetry between the producer and the consumer 1.1 CLOUD COMPUTING IN A NUTSHELL

65 The Bounded-Buffer Problem (cont.)
The consumer producing empty buffers for the producer 1.1 CLOUD COMPUTING IN A NUTSHELL

66 Monitors Semaphores provide a convenient and effective mechanism for synchronization Using them incorrectly can result in timing errors that are difficult to detect These errors happen only if particular execution sequences take place These sequences do not always occur e.g., The use of counters in the solution to the producer-consumer problem The timing problem happened only rarely Even then the counter value appeared to be reasonable, off by only 1 The solution is obviously not an acceptable one 1.1 CLOUD COMPUTING IN A NUTSHELL

67 Monitors (cont.) Such timing errors can still occur when semaphores are used e.g., In the semaphore solution to the critical-section problem All processes share a semaphore variable mutex, which is initialized to 1 Each process must execute wait(mutex) before entering the critical section And signal(mutex) afterward If this sequence is not observed, two processes may be in their critical sections simultaneously The above difficulties will arise even if a single process is not well behaved 1.1 CLOUD COMPUTING IN A NUTSHELL

68 Monitors (cont.) May be caused by an honest programming error or an uncooperative programmer e.g., A process interchanges the order in which the wait() and signal() operations on the semaphore mutex are executed Several processes may be executing in their critical sections simultaneously, violating the mutual-exclusion requirement This error may be discovered only if several processes are simultaneously active in their critical sections 1.1 CLOUD COMPUTING IN A NUTSHELL

69 Monitors (cont.) This situation may not always be reproducible e.g., A process replaces signal(mutex) with wait(mutex) In this case, a deadlock will occur e.g., A process omits the wait(mutex), or the signal(mutex), or both In this case, either mutual exclusion is violated or a deadlock will occur Various types of errors can be generated easily 1.1 CLOUD COMPUTING IN A NUTSHELL

70 Monitors (cont.) To deal with such errors
When programmers use semaphores incorrectly to solve the critical-section problem Similar problems may arise in the other synchronization models To deal with such errors Researchers have developed high-level language constructs One fundamental high-level synchronization construct is the monitor type 1.1 CLOUD COMPUTING IN A NUTSHELL

71 Monitor Usage An abstract data type, or ADT A monitor type is an ADT
Encapsulates data with a set of functions to operate on that data The data are independent of any specific implementation of the ADT A monitor type is an ADT Includes a set of programmer-defined operations Provided with mutual exclusion within the monitor Also declares the variables whose values define the state of an instance of that type Along with the bodies of functions that operate on those variables The syntax of a monitor type 1.1 CLOUD COMPUTING IN A NUTSHELL

72 Monitor Usage (cont.) 1.1 CLOUD COMPUTING IN A NUTSHELL

73 Monitor Usage (cont.) The representation of a monitor type cannot be used directly by the various processes A function defined within a monitor can access only those variables declared locally within the monitor and its formal parameters The local variables of a monitor can be accessed by only the local functions Only one process at a time is active within the monitor The programmer does not need to code this synchronization constraint explicitly The monitor construct is not sufficiently powerful for modeling some synchronization schemes Need to define additional synchronization mechanisms 1.1 CLOUD COMPUTING IN A NUTSHELL

74 Monitor Usage (cont.) 1.1 CLOUD COMPUTING IN A NUTSHELL

75 Monitor Usage (cont.) These mechanisms are provided by the condition construct A programmer who needs to write a tailor-made synchronization scheme can define one or more variables of type condition condition x, y; The only operations that can be invoked on a condition variable are wait() and signal() The operation x.wait(); The process invoking this operation is suspended until another process invokes x.signal(); The x.signal() operation resumes exactly one suspended process 1.1 CLOUD COMPUTING IN A NUTSHELL

76 Monitor Usage (cont.) If no process is suspended, the signal() operation has no effect The state of x is the same as if the operation had never been executed The signal() operation associated with semaphores always affects the state of the semaphore When the x.signal() operation is invoked by a process P Suppose there exists a suspended process Q associated with condition x When thread P executes the signal operation It immediately leaves the monitor Q is immediately resumed 1.1 CLOUD COMPUTING IN A NUTSHELL

77 Monitor Usage (cont.) 1.1 CLOUD COMPUTING IN A NUTSHELL

78 Implementing a Monitor Using Semaphores
A possible implementation of the monitor mechanism using semaphores For a monitor, a semaphore mutex is provided Initialized to 1 A process must execute wait(mutex) before entering the monitor And must execute signal(mutex) after leaving the monitor A signaling process of some condition must wait until the resumed process either leaves or waits An additional semaphore, next, is introduced Initialized to 0 The signaling processes can use next to suspend themselves 1.1 CLOUD COMPUTING IN A NUTSHELL

79 Implementing a Monitor Using Semaphores (cont.)
An integer variable next_count is also provided To count the number of processes suspended on next Each external function F is replaced by Mutual exclusion within a monitor is ensured How condition variables are implemented For each condition x 1.1 CLOUD COMPUTING IN A NUTSHELL

80 Implementing a Monitor Using Semaphores (cont.)
Introduce a semaphore x_sem and an integer variable x_count, both initialized to 0 The operation x.wait() can be implemented as The operation x.signal() can be implemented as 1.1 CLOUD COMPUTING IN A NUTSHELL

81 Resuming Processes within a Monitor
Process-resumption order within a monitor If several processes are suspended on condition x, and an x.signal() operation is executed by some process Determine which of the suspended processes should be resumed next One simple solution is to use a first-come, first-served (FCFS) ordering The process that has been waiting the longest is resumed first In many circumstances, such a simple scheduling scheme is not adequate The conditional-wait construct can be used x.wait(c); 1.1 CLOUD COMPUTING IN A NUTSHELL

82 Resuming Processes within a Monitor (cont.)
c is an integer expression Evaluated when the wait() operation is executed The value of c is called a priority number Stored with the name of the process that is suspended When x.signal() is executed The process with the smallest priority number is resumed next The ResourceAllocator monitor Controls the allocation of a single resource among competing processes When requesting an allocation of this resource Each process specifies the maximum time it plans to use the resource 1.1 CLOUD COMPUTING IN A NUTSHELL

83 Resuming Processes within a Monitor (cont.)
The monitor allocates the resource to the process that has the shortest time-allocation request A process that needs to access the resource in question must observe the following sequence R is an instance of type ResourceAllocator The monitor concept cannot guarantee that the preceding access sequence will be observed A process might access a resource without first gaining access permission to the resource A process might never release a resource once it has been granted access to the resource 1.1 CLOUD COMPUTING IN A NUTSHELL

84 Resuming Processes within a Monitor (cont.)
1.1 CLOUD COMPUTING IN A NUTSHELL

85 Resuming Processes within a Monitor (cont.)
A process might attempt to release a resource that it never requested A process might request the same resource twice, (first releasing the resource One possible solution to the above problem To include the resource-access operations within the ResourceAllocator monitor Scheduling is done according to the built-in monitor-scheduling algorithm rather than the one we have coded Not reasonable for a large system or a dynamic system This access-control problem can be solved only through the use of the additional mechanisms 1.1 CLOUD COMPUTING IN A NUTSHELL

86 Synchronization in Linux
The Linux kernel is fully preemptive A task can be preempted when it is running in the kernel Linux provides some different mechanisms for synchronization in the kernel Most computer architectures provide instructions for atomic versions of simple math operations The simplest synchronization technique within the Linux kernel is an atomic integer Represented using the opaque data type atomic_t All math operations using atomic integers are performed without interruption 1.1 CLOUD COMPUTING IN A NUTSHELL

87 Synchronization in Linux (cont.)
The code declares an atomic integer counter and performing atomic operations Particularly efficient in situations below e.g., An integer variable, like a counter, needs to be updated Atomic operations do not require the overhead of locking mechanisms 1.1 CLOUD COMPUTING IN A NUTSHELL

88 Synchronization in Linux (cont.)
Their usage is limited to these sorts of scenarios In situations where there are several variables contributing to a possible race condition More sophisticated locking tools must be used The signal is the standard Linux mechanism For informing a process that an event has occurred Can be sent from a process to any other process With restrictions on signals sent to processes owned by another user Only a limited number of signals are available Cannot carry information Only the fact that a signal has occurred is available to a process 1.1 CLOUD COMPUTING IN A NUTSHELL

89 Synchronization in Linux (cont.)
Signals are not generated only by a process The kernel also generates signals internally e.g., Can send a signal to a server process when data arrive on a network channel To a parent process when a child terminates Or to a waiting process when a timer expires The kernel does not use signals to communicate with processes running in kernel mode If a kernel-mode process is expecting an event to occur, it will not use signals to receive notification Communication about incoming asynchronous events within the kernel takes place through the use of scheduling states and wait_queue structures These mechanisms allow kernel-mode processes to inform one another about relevant events 1.1 CLOUD COMPUTING IN A NUTSHELL

90 Synchronization in Linux (cont.)
Also allow events to be generated by device drivers or by the networking system Whenever a process wants to wait for some event to complete Places itself on a wait queue associated with the event Tells the scheduler that it is no longer eligible for execution Once the event has completed Every process on the wait queue will be awoken Allows multiple processes to wait for a single event e.g., If several processes are trying to read a file from a disk They will all be awakened once the data have been read into memory successfully 1.1 CLOUD COMPUTING IN A NUTSHELL

91 Synchronization in Linux (cont.)
Signals have been the main mechanism For communicating asynchronous events Linux also implements the semaphore mechanism of System V UNIX A process can wait on a semaphore as easily as it can wait for a signal Semaphores have two advantages Large numbers of semaphores can be shared among multiple independent processes Operations on multiple semaphores can be performed atomically Internally, the standard Linux wait queue mechanism synchronizes processes that are communicating with semaphores 1.1 CLOUD COMPUTING IN A NUTSHELL

92 Synchronization in Linux (cont.)
Mutex_locks are available in Linux For protecting critical sections within the kernel A task must invoke the mutex_lock() function prior to entering a critical section Invoking the mutex_unlock() function after exiting the critical section If the mutex_lock is unavailable A task calling mutex_lock() is put into a sleep state Awakened when the lock’s owner invokes mutex_unlock() Linux also provides spinlocks and semaphores for locking in the kernel On multiprocessor machines, the fundamental locking mechanism is a spinlock 1.1 CLOUD COMPUTING IN A NUTSHELL

93 Synchronization in Linux (cont.)
The kernel is designed so that the spinlock is held only for short durations On single-processor machines Such as embedded systems with only a single processing core Spinlocks are inappropriate for use Replaced by enabling and disabling kernel preemption On single-processor systems Rather than holding a spinlock, the kernel disables kernel preemption Rather than releasing the spinlock, it enables kernel preemption 1.1 CLOUD COMPUTING IN A NUTSHELL

94 Synchronization in Linux (cont.)
How Linux disables and enables kernel preemption Provides two simple system calls preempt_disable() and preempt_enable() for disabling and enabling kernel preemption The kernel is not preemptible If a task running in the kernel is holding a lock Each task in the system has a thread-info structure containing a counter, preempt_count To indicate the number of locks being held by the task As a lock is acquired, preempt count is incremented It is decremented when a lock is released As this task currently holds a lock, not safe to preempt the kernel 1.1 CLOUD COMPUTING IN A NUTSHELL

95 Synchronization in Linux (cont.)
If the value of preempt count for the task currently running in the kernel is greater than 0 If the count is 0 The kernel can safely be interrupted If there are no outstanding calls to preempt_disable() Spinlocks along with enabling and disabling kernel preemption Used in the kernel only when a lock or disabling kernel preemption is held for a short duration When a lock must be held for a longer period Semaphores or mutex locks are appropriate for use The way the kernel schedules its operations Fundamentally different from the way it schedules processes 1.1 CLOUD COMPUTING IN A NUTSHELL

96 Synchronization in Linux (cont.)
A request for kernel-mode execution can occur in two ways A running program may request an OS service Either explicitly via a system call Or implicitly, e.g., when a page fault occur A device controller may deliver a hardware interrupt The CPU to start executing a kernel-defined handler for that interrupt All these tasks may try to access the same internal data structures If one kernel task is in the middle of accessing some data structure as an interrupt service routine executes 1.1 CLOUD COMPUTING IN A NUTSHELL

97 Synchronization in Linux (cont.)
That service routine cannot access or modify the same data without risking data corruption Relates to the idea of critical sections Portions of code that access shared data must not be allowed to execute concurrently Kernel synchronization involves much more than just process scheduling A framework is required to allow kernel tasks to run without violating the integrity of shared data The second protection technique used by Linux Applies to critical sections that occur in interrupt service routines 1.1 CLOUD COMPUTING IN A NUTSHELL

98 Synchronization in Linux (cont.)
The basic tool is the processor’s interrupt-control hardware By disabling interrupts or using spinlocks during a critical section The kernel guarantees that it can proceed without the risk of concurrent access to shared data structures There are penalties for disabling interrupts On most hardware architectures, interrupt enable and disable instructions are not cheap As long as interrupts remain disabled, all I/O is suspended Any device waiting for servicing will have to wait until interrupts are reenabled; thus, performance degrades The Linux kernel uses a synchronization architecture 1.1 CLOUD COMPUTING IN A NUTSHELL

99 Synchronization in Linux (cont.)
Allows long critical sections to run for their entire duration without having interrupts disabled This ability is especially useful in the networking code An interrupt in a network device driver can signal the arrival of an entire network packet May result in a great deal of code being executed to disassemble, route, and forward that packet within the interrupt service routine Linux separates interrupt service routines into two sections The top half and the bottom half The top half is the standard interrupt service routine that runs with recursive interrupts disabled 1.1 CLOUD COMPUTING IN A NUTSHELL

100 Synchronization in Linux (cont.)
Interrupts of the same number or line are disabled But other interrupts may run The bottom half of a service routine is run with all interrupts enabled by a miniature scheduler Ensures that bottom halves never interrupt themselves The bottom-half scheduler is invoked automatically whenever an interrupt service routine exits The kernel can complete any complex processing that has to be done in response to an interrupt without worrying about being interrupted itself If another interrupt occurs while a bottom half is executing That interrupt can request that the same bottom half execute 1.1 CLOUD COMPUTING IN A NUTSHELL

101 Synchronization in Linux (cont.)
But the execution will be deferred until the one currently running completes Each execution of the bottom half can be interrupted by a top half Can never be interrupted by a similar bottom half The top-half/bottom-half architecture Completed by a mechanism for disabling selected bottom halves While executing normal foreground kernel code The kernel can code critical sections easily using this system Interrupt handlers can code their critical sections as bottom halves 1.1 CLOUD COMPUTING IN A NUTSHELL

102 Synchronization in Linux (cont.)
When the foreground kernel wants to enter a critical section, it can disable any relevant bottom halves to prevent any other critical sections from interrupting it At the end of the critical section, the kernel can reenable the bottom halves Run any bottom-half tasks that have been queued by top-half interrupt service routines during the critical section The various levels of interrupt protection within the kernel Each level may be interrupted by code running at a higher level Never be interrupted by code running at the same or a lower level 1.1 CLOUD COMPUTING IN A NUTSHELL

103 Synchronization in Linux (cont.)
User processes can always be preempted by another process when a time-sharing scheduling interrupt occurs Except for user-mode code 1.1 CLOUD COMPUTING IN A NUTSHELL


Download ppt "Chapter 5 Synchronization"

Similar presentations


Ads by Google