• No se han encontrado resultados

Critical section: A section of code within a process that requires access to shared resources and that must not be executed while another process is in a corresponding section of code.

The execution of critical sections by the processes is mutually exclusive in time.

The critical-section problem is to design a protocol, that the processes can use to cooperate.

Each process must request permission to enter its critical section. The section of code implementing this request is the entry section.

The critical section may be followed by an exit section. The remaining code is the remainder section.

The general structure of a typical process Pi is shown in following code.

do{

Critical section

remainder section } while (TRUE);

A solution to the critical section problem must satisfy the following 3 requirements.

I. Mutual exclusion:

If process Pi is executing in its critical section, then no other processes can be executed in their critical sections.

II. Progress:

If no process is executing in its critical section and some processes wish to enter their critical sections, then only those processes that are not executing in their remainder sections can participate in the decision on which will enter its critical section next, and this section cannot be postponed indefinitely.

III. Bounded waiting:

There exists a bound, or limit, on the number of times that other processes are allowed to enter their critical section after a process has made a request to enter its critical section and before that request is granted.

Peterson’s solution

A classic software-based solution to the critical section problem known as Peterson’s solution We restrict our attention to algorithms that are applicable to only two processes at a time the processes are numbered P0 and P1. For convenience, when presenting Pl we use Pj to denote the other process; i.e. j = 1 – i.

Note: Below is an algorithm for two processes. It can be generalized for n processes.

Algorithm 1

 Shared variables:

int turn;

initiallyturn = 0

turn = I; Pi can enter its critical section exit section

entry section

 Process Pi do{

while (turn != i) ; critical section turn = j;

reminder section } while (1);

 Satisfies mutual exclusion, but not progress

Algorithm 2

 Shared variables boolean flag[2];

initiallyflag [0] = flag [1] = false.

flag [i] = true; Pi ready to enter its critical section

 Process Pi do {

flag[i] := true;

while (flag[j]) ; critical section flag [i] = false;

remainder section } while (1);

 Satisfies mutual exclusion, but not progress requirement.

Algorithm 3

 Combined shared variables of algorithms 1 and 2.

 Process Pi do{

flag [i]:= true;

turn = j;

while (flag [j] and turn = j) ; critical section flag [i] = false;

remainder section } while (1);

 Meets all three requirements; solves the critical-section problem for two processes 2. Synchronization hardware

Many machines provide special hardware instructions that allow us either to test and modify the content of a word or to swap the contents of two words, atomically – that is, as one uninterruptable unit.

The Test And Set instruction can be defined as follows:

boolean Test And Set (boolean& lock) {

boolean r;

r = lock;

lock = true;

return r;

}

If lock is true then we can’t enter in to critical section Initially lock = false.

while (Test And Set (lock)) critical section

lock = false ;

In above method problem is busy waiting, because when lock is true then process continues execute that instruction.

(i) Swap instruction

void swap (boolean a, boolean b) {

boolean c;

c = a;

b = c;

return b;

}

A global Boolean variable lock is declared and is initialized to false.

In above also problem of busy waiting 3. Semaphores

A semaphores S is an integer variable that, apart from initialization, is accessed only through two standard atomic operations: wait ( )and signal( ). These operations were originally termed P (for wait) and V (for signal)

The classical definition of wait in pseudo code is:

wait (s) {

while ( s 0 )

// keep waiting

s = s – 1;

}

The classical definitions of signal in pseudo code is:

signal (s) {

s = s + 1;

}

A binary semaphore is a semaphore where count may only take on the value of 1 or 0.

A semaphores which can take on any non negative value may be referred to as general semaphores or counting semaphores.

Let S be a counting semaphore. To implement it in term of binary semaphores we need the following data structure:

lock = false ;

while (swap (lock, true)) critical section

lock = false ;

binary semaphore S1, S2;

int C ;

Initially S1 = 1, S2 = 0, and the value of integer C is set to the initial value of the counting semaphore S.

The wait operation on the counting semaphore S can be implemented as follows:

Wait (S1);

C - - ; if(C )

Signal (S1);

Wait (S2);

} else

Signal(S2);

The signal operation on the counting semaphore s can be implemented as follows:

Wait (S1);

C + +;

if (C < = 0)

Signal(S2) ; else

Signal(S1);

The main disadvantage of the mutual-exclusion solutions and the semaphores definition given here, is that they all require busy waiting.

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 entry code. This continual looping is clearly a problem in a real multiprogramming system, where a single CPU is shared among many process.

Busy waiting wastes CPU cycle that some other process might be able to use productively. This type of semaphore is also called a spinlock. Spinlocks are useful in multiprocessor systems.

When two or more process are waiting indefinitely for an event that can be caused only by one of the waiting processes, these processes are said to be deadlocked.

Another problem related to deadlocks is indefinite blocking or starvation, a situation where processes wait indefinitely within the semaphore.

Classic Problem of Synchronization

I. Classical Producer consumer problem with bounded buffer.

semaphore mutex = 1

semaphore can_produce = n = 5 = buffer size semaphore can_consume = 0

For unbounded buffer remove wait ( can produce) from produce code.

(i) Readers- writers problems

(a) If reader come and reader available then no problem.

(b) If writer available then reader and writer have to wait.

Reader_count = 0

Wait(mutex);

reader count - - ; If( reader count = = 0) Signal (s) ;

Signal(mutex);

II. The Dining – Philosophers problem:

Consider five philosophers who spend their lives thinking and eating. The philosophers share a common circular table surrounded by five chairs, each belonging to one philosopher.

In the center of the table is a bowl of rice, and the table is laid with five single chopsticks.

When a philosopher thinks, she does not interact with her colleagues.

From time to time, a philosopher gets hungry and tries to pick up the two chopsticks that are closest to her.

When a hungry philosopher has both her chopsticks at same time, she eats without releasing her chopsticks.

When she finishes eating, she puts down both of her chopsticks and starts thinking again.

One simple solution is to represent each chopstick by a semaphore. A philosopher tries to grab the chopsticks by executing a wait operation on that semaphore; she releases her appropriate semaphore.

Thus the shared data are Semaphore chopsticks [5];

Where all the element of chopsticks are initialized to 1.

do {

wait (chopstick [i]);

wait (chopstick[(i+1)%5]);

…… eat

Signal (chopstick [i]);

Signal (chopstick [ (i+1)% 5]);

……

Think

} while (1);

Although this solution guarantees that no two neighbors are eating simultaneously, it nevertheless must be rejected because it has the possibility of creating a deadlock.

Suppose that all five philosophers become hungry simultaneously, and each grabs her left chopsticks. All the elements of chopsticks will now be equal to 0. When each philosopher tries to grab her right chopstick, she will be delayed forever.

Solution that ensure freedom from deadlocks:

(i) Allow atmost four philosophers to be sitting simultaneously at the table.

(ii) Allow a philosopher to pick up her chopsticks only if both chopsticks are available.

(iii) A symmetric solution: An odd philosopher picks up first her left chopsticks and then her right chopstick, whereas an even philosopher pick up her right chopstick and than her left chopstick.

(iv) One should be right handed (first pick right chopsticks) and all other left handed or vice versa.

Monitors

 A high-level abstraction that provides a convenient and effective mechanism for process synchronization.

 Only one process may be active with in the monitor at a time

Monitor Monitor name

{ || shared variable declarations procedure p1 (…) …}

……

procedure pn(…) …}

initialization code (…) …}

…….

}

 Schematic view of a monitor

 Condition Variables

 Condition x, y:

 Two operations on condition variables:

 x.wait( ) –a process that invoked the operation is suspended

 x. signal ( ) – resumes one of processes that invoked x.wait ( )

 Monitor wit condition variables

,

4.3: Threads

A thread is a single sequence stream within a process. It inhibits some properties of the process, therefore it is sometimes termed as a light weight process (LWP) which is a basic unit of CPU utilization.

It comprises of a thread ID, a program counter, a register set, and a stack.

It shares with other threads belonging to the same process its code section, data section, and other operating-system resources, such as open files and signals.

If the process has multiple threads of control, it can do more than one task at a time.

Fig. 4.3.1 Single and multi threaded processes

Benefits of multithreaded programming

1. Responsiveness: Multithreading is an interactive application which may allow a program to continue running even if part of it is blocked or is performing a lengthy operation.

2. Resource sharing: Threads share the memory and the resources of the process to which they belong.

3. Economy: Threads share resources, so it is more economical to create and context switch threads.

4. Utilization of multiprocessor architecture: The benefits of multithreading can be greatly increased in a multiprocessor architecture, where each thread may be running in parallel on a different processors.

Table 4.3.1 Comparison of User-level Thread & Kernel-level Thread

S. No User – level Thread Kernel – level Thread i. It is managed and supported by

the user. There is no intervention of Kernel.

It is managed and supported by the operating system. Here, kernel manages the thread.

User – level Thread Kernel – level Thread Libraries: POSIX Pthread, mach C-thread, and

solaries 2 U1 – threads.

window (NT, 2000) solaries 2, BeOS, and Tru 64.

Multithreading Models:

1. Many to one model : The many-to-one model maps many user-level threads to one kernel thread. Thread management is done in user space. So, it is efficient, but the entire process will block if a thread makes a blocking system call.

Green threads – a thread library available for Solaris 2 uses this model.

2. One-to-one model: The One-to-One model maps each user thread to a kernel thread. It provides more concurrency than the many-to-one model by allowing another thread to run when a thread makes a blocking system call.

3. Many-to-many model: This model multiplexes many user-level threads to a smaller or equal number of kernel threads.

User thread

Kernel thread

K K K

Fig. 4.3.4

Kernel thread

K K K

User thread

Fig. 4.3.3 K

User thread

Kernel thread Fig. 4.3.2

Documento similar