3 04/18/23
chapter 7: Process Synchronization
Background 背景 The Critical-Section Problem 临界区问题 Synchronization Hardware 同步的硬件实现 Semaphores信号量
4 04/18/23
Classical Problems of Synchronization经典同步问题 Monitors 管程 Java SynchronizationJava中的同步机制 Synchronization in Solaris 2 Solaris 2的同步机制 Synchronization in Windows NT Windows NT的同步机制
5 04/18/23
Background
Concurrent access to shared data may result in data inconsistency(对共享数据的并发访问可能导致数据的不一致性) .
Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes(要保持数据的一致性,就需要一种保证并发进程的正确执行顺序的机制) .
6 04/18/23
例:共享内存问题
Shared-memory solution to bounded-butter problem (Chapter 4) has a race condition on the class data count
[ 第 4 章 P83中 ]解决有界缓冲区问题的共享内存方法,对循环队列的操作,我们在此引入一变量, count,表示缓冲池中空闲块的数目。
7 04/18/23
Bounded-Buffer
Shared data#define BUFFER_SIZE 10typedef struct {. . .
} item;item buffer[BUFFER_SIZE];int in = 0;int out = 0;int counter = 0;
8 04/18/23
Bounded-Buffer
Producer process item nextProduced;while (1) {
while (counter == BUFFER_SIZE); /* do nothing */
buffer[in] = nextProduced;in = (in + 1) % BUFFER_SIZE;counter++;
}
9 04/18/23
Bounded-Buffer
Consumer process item nextConsumed;while (1) {
while (counter == 0); /* do nothing */
nextConsumed = buffer[out];out = (out + 1) % BUFFER_SIZE;counter--;
}
10 04/18/23
Bounded Buffer
The statements
counter++;counter--;must be performed atomically.
Atomic operation means an operation that completes in its entirety without interruption.
11 04/18/23
Bounded Buffer
The statement “count++” may be implemented in machine language as:
register1 = counterregister1 = register1 + 1counter = register1
12 04/18/23
The statement “count—” may be implemented as:
register2 = counterregister2 = register2 – 1counter = register2
13 04/18/23
Bounded Buffer
If both the producer and consumer attempt to update the buffer concurrently, the assembly language statements may get interleaved(交错) .
Interleaving depends upon how the producer and consumer processes are scheduled.
14 04/18/23
Bounded Buffer
Assume counter is initially 5. One interleaving of statements is:
producer: register1 = counter (register1 = 5)producer: register1 = register1 + 1 (register1 = 6)consumer: register2 = counter (register2 = 5)consumer: register2 = register2 – 1 (register2 = 4)producer: counter = register1 (counter = 6)consumer: counter = register2 (counter = 4)
The value of count may be either 4 or 6, where the correct result should be 5.
15 04/18/23
Race Condition竟争条件
Race condition: The situation where several processes access – and manipulate shared data concurrently. The final value of the shared data depends upon which process finishes last.
To prevent race conditions, concurrent processes must be synchronized.
16 04/18/23
The Critical-Section Problem
n processes all competing to use some shared data
Each process has a code segment, called critical section, in which the shared data is accessed.
Problem – ensure that when one process is executing in its critical section, no other process is allowed to execute in its critical section.
17 04/18/23
Solution to Critical-Section Problem
1. Mutual Exclusion. If process Pi is executing in its critical section, then no other processes can be executing in their critical sections
2.Progress. If no process is executing in its critical section and there exist some processes that wish to enter their critical section, then the selection of the processes that will enter the critical section next cannot be postponed indefinitely
18 04/18/23
3. Bounded Waiting. A bound must exist on the number of times that other processes are allowed to enter their critical sections after a process has made a request to enter its critical section and before that request is granted.
19 04/18/23
互斥条件。假定进程 Pi在其临界区内执行,其他任何进程将被排斥在自己的临界区之外 .
有空让进。临界区虽没有进程执行,但有些进程需要进入临界区,不能无限期地延长下一个要进入临界区进程的等待时间 .
有限等待。在一个进程提出进入临界区的请求和该请求得到答复的时间内,其他进程进入临界区前的等待时间必须是有限的
20 04/18/23
进程同步问题解必须遵循:
Assume that each process executes at a nonzero speed (假定每个进程都以非零的的速率执行) .
No assumption concerning relative speed of the n processes(没有任何关于这 n 个进程相对执行速率的假定) .
21 04/18/23
Initial Attempts to Solve Problem
General structure of process Pi (other process Pj)
do {entry section
critical sectionexit section
reminder section} while (1);
22 04/18/23
Two-process solutions
Only 2 processes, P0 and P1
Processes may share some common variables to synchronize their actions.
23 04/18/23
Algorithm 1
Shared variables: int turn;initially turn = 0
turn =i Pi can enter its critical section Process Pi
do {while (turn != i) ;critical section
turn = j;reminder section
} while (1); Satisfies mutual exclusion, but not progress
24 04/18/23
Algorithm 2 Shared variables
boolean flag[2];initially flag [0] = flag [1] = false.
flag [i] = true Pi ready to enter its critical section
Process Pi
do {flag[i] := true;while (flag[j]) ;critical sectionflag [i] = false;remainder section} while (1);
Satisfies mutual exclusion, but not progress requirement.
25 04/18/23
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.
26 04/18/23
Bakery Algorithm
Before entering its critical section, process receives a number. Holder of the smallest number enters the critical section.
If processes Pi and Pj receive the same number, if i < j, then Pi is served first; else Pj is served first.
The numbering scheme always generates numbers in increasing order of enumeration; i.e., 1,2,3,3,3,3,4,5...
Critical section for n processes
27 04/18/23
Bakery Algorithm
Notation < lexicographical order (ticket #, process id #) (a,b) < c,d) if a < c or if a = c and b < d max (a0,…, an-1) is a number, k, such that k
ai for i - 0, …, n – 1
Shared databoolean choosing[n];int number[n];
Data structures are initialized to false and 0 respectively
28 04/18/23
Bakery Algorithm do { choosing[i] = true;number[i] = max(number[0], number[1], …, number [n – 1])+1;choosing[i] = false;for (j = 0; j < n; j++) {
while (choosing[j]) ; while ((number[j] != 0) &&
(number[j],j) < number[i],i)) ;}
critical sectionnumber[i] = 0;
remainder section} while (1);
29 04/18/23
Synchronization Hardware
Test and modify the content of a word atomically.
boolean TestAndSet(boolean &target) {
boolean rv = target;tqrget = true;
return rv;}
30 04/18/23
Semaphore
Semaphore S – integer variable(信号量 S – 整型变量 spinlock自旋锁)
Apart from initialization, semaphore S can only be accessed via two indivisible (atomic) operations(除初始化外,仅能通过两个不可分割的[原子 ]操作访问)
wait(S):while S 0 do no-op;S--;
signal(S): S++;
31 04/18/23
Critical Section of n Processes
Shared data: semaphore mutex; //initially mutex = 1
Process Pi:
do { wait(mutex); critical section
signal(mutex); remainder section} while (1);
32 04/18/23
Usage semphores to solve synchronization
用信号量解决同步问题的一般框架 P1 :… S1
signal(synch); P2: … wait(synch); S2
S1 S2
33 04/18/23
Semaphore Implementation
Define a semaphore as a recordtypedef struct { int value; struct process *L;} semaphore;
Assume two simple operations: block suspends the process that invokes it.
wakeup(P) resumes the execution of a blocked process P.
这两操作都是由操作系统提供系统调用实现。
34 04/18/23
Implementation
Semaphore operations now defined as wait(S):
S.value--;if (S.value < 0) {
add this process to S.L;block;
}
signal(S): S.value++;if (S.value <= 0) {
remove a process P from S.L;wakeup(P);
}
35 04/18/23
信号量的关键之处是它们原子地执行,必须保证没有两个进程能同时对信号量执行wait(),signal()操作。 在单处理器下,可以在执行操作wait(),signal()时简单地禁止中断,这是因为一旦禁止中断,在单处理器下,不同的指令不会交织在一起,但在多处理器下,禁止中断是毫无作用的,来自不同进程的指令可以以任何方式交织在一起。
信号量的值为负时,其绝对值为在该信号量下等待的进程数目。
36 04/18/23
死锁和饥饿 死锁 – 两个或多个进程无限期地等待一个事件的
发生,而该事件正是由其中的一个等待进程引起的) . Let S and Q be two semaphores initialized to 1( S 和 Q 是两个初值为 1的信号量)
P0 P1
P(S); P(Q);P(Q); P(S);
V(S); V(Q);V(Q) V(S);
37 04/18/23
死锁和饥饿
Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended(饥饿 – 无限期地阻塞。进程可能永远无法从它等待的信号量队列中移去) .
38 04/18/23
Two Types of Semaphores
Counting semaphore – integer value can range over an unrestricted domain(计数信号量 – 变化范围没有限制的整型值) .
Binary semaphore – integer value can range only between 0 and 1; can be simpler to implement(二值信号量 – 变化范围仅限于 0和 1的信号量;容易实现).
Can implement a counting semaphore S as a binary semaphore(可以将计数信号量S用作二值信号量).
39 04/18/23
Implementing S
wait operationwait(S1);C--;if (C < 0) {
signal(S1);wait(S2);
}signal(S1);
signal operationwait(S1);C ++;if (C <= 0)
signal(S2);else
signal(S1);
40 04/18/23
Classical Problems of Synchronization
Bounded-Buffer Problem (有限缓冲区问题) Readers and Writers Problem (读者写者问题) Dining-Philosophers Problem (哲学家就餐问题)
41 04/18/23
Bounded-Buffer Problem
Shared data
semaphore full, empty, mutex;
Initially:
full = 0, empty = n, mutex = 1
42 04/18/23
Bounded-Buffer Problem Producer Process
do { …
produce an item in nextp …
wait(empty);wait(mutex); …
add nextp to buffer …
signal(mutex);signal(full);
} while (1);
43 04/18/23
Bounded-Buffer Problem Consumer Process
do { wait(full)wait(mutex); …remove an item from buffer to nextc …signal(mutex);signal(empty); …consume the item in nextc …
} while (1);
44 04/18/23
Readers-Writers Problem
第一类读者问题:没有要求有读者需要等待除非一个写者已被允许使用共享对象。
第二类读者问题:只要有一个写者在等待访问对象,那么不会有新的读者开始读操作。
二类读者写者问题都可能导致饥饿。
Shared datasemaphore mutex, wrt;Initiallymutex = 1, wrt = 1, readcount = 0
46 04/18/23
Readers-Writers Problem Reader Process
wait(mutex);readcount++;if (readcount == 1)
wait(wrt);signal(mutex);
…reading is performed …
wait(mutex);readcount--;if (readcount == 0)signal(wrt);
signal(mutex):
47 04/18/23
Dining-Philosophers Problem
Shared data semaphore chopstick[5];
Initially all values are 1
48 04/18/23
Dining-Philosophers Problem
Philosopher i:do {wait(chopstick[i])wait(chopstick[(i+1) % 5]) …eat …
signal(chopstick[i]);signal(chopstick[(i+1) % 5]); …think …
} while (1);
49 04/18/23
Monitors A monitor is a high-level abstraction that provides thread safety(管程是对提供线程安全机制的高度抽象) .
Only one thread may be active within the monitor at a time(任一时刻在管程中只有一个线程是能运行的) .
50 04/18/23
管程的抽象类型定义monitor monitor-name
{shared variable declarationsprocedure body P1 (…) {
. . .}
procedure body P2 (…) {. . .
} procedure body Pn (…) {
. . .}
{ initialization code}
}
51 04/18/23
Condition Variables
condition x, y;
A thread that invokes x.wait is suspended until another thread invokes x.signal(调用 x.wait的线程将一直等待到有另一个线程 调用x.signal)
54 04/18/23
Dining Philosophers Example
monitor dp {
enum {thinking, hungry, eating} state[5];
condition self[5];void pickup(int i) void putdown(int i)void test(int i) void init() {
for (int i = 0; i < 5; i++)state[i] = thinking;
}}
55 04/18/23
Dining Philosophers
void pickup(int i) {state[i] = hungry;test[i];if (state[i] != eating)
self[i].wait();}
void putdown(int i) {state[i] = thinking;// test left and right neighborstest((i+4) % 5);test((i+1) % 5);
}
56 04/18/23
Dining Philosophers
void test(int i) {if ( (state[(i + 4) % 5] != eating)
&& (state[i] == hungry) && (state[(i + 1) % 5] != eating)) {
state[i] = eating;self[i].signal();
}}
57 04/18/23
Java Synchronization
Synchronized, wait(), notify() statements(同步化, wait(), notify()语句)
Multiple Notifications(多重声明) Block Synchronization(大块程序的同步化)
Java Semaphores( Java信号量) Java Monitors( Java管程)
58 04/18/23
synchronized Statement
Every object has a lock associated with it(每个对象都有与之相关联的锁) .
Calling a synchronized method requires “owning” the lock(只有拥有这把锁的方法才能称为同步化进程) .
If a calling thread does not own the lock (another thread already owns it), the calling thread is placed in the wait set for the object’s lock(如果主调线程没有这把锁, [而其他线程有了 ],主调线程就会进入该物体的等待集)
The lock is released when a thread exits the synchronized method(当线程退出了同步化方法时锁就会释放).
60 04/18/23
synchronized enter() Method
public synchronized void enter(Object item) {while (count == BUFFER_SIZE)
Thread.yield();++count;buffer[in] = item;in = (in + 1) % BUFFER_SIZE;
}
61 04/18/23
synchronized remove() Method
public synchronized Object remove() {Object item;while (count == 0)
Thread.yield();--count;item = buffer[out];out = (out + 1) % BUFFER_SIZE;return item;
}
62 04/18/23
The wait() Method
When a thread calls wait(), the following occurs(当线程调用 wait()时,会产生以下动作) :- the thread releases the object lock(该线程释放对象锁) .- thread state is set to blocked(线程状态置为阻塞) .- thread is placed in the wait set(线程进入等待集) .
64 04/18/23
The notify() Method
When a thread calls notify(), the following occurs(当线程调用 notify()时,会产生以下动作) :- selects an arbitrary thread T from the wait set(任意从等待集中选出一个线程 T.- moves T to the entry set(将 T 置入入口集).- sets T to Runnable(设置T 为可运行状态).
T can now compete for the object’s lock again(此时,T 又能竞争使用对象锁了).
65 04/18/23
enter() with wait/notify Methods
public synchronized void enter(Object item) {while (count == BUFFER_SIZE)
try {wait();
} catch (InterruptedException e) { }
}++count;buffer[in] = item;in = (in + 1) % BUFFER_SIZE;notify();
}
66 04/18/23
remove() with wait/notify Methods
public synchronized Object remove() {Object item;while (count == 0)
try {wait();}catch (InterruptedException e) { }
--count;item = buffer[out];out = (out + 1) % BUFFER_SIZE;notify();return item;
}
67 04/18/23
Multiple Notifications
notify() selects an arbitrary thread from the wait set. *This may not be the thread that you want to be selected ( notify()从等待集中任意选取一个线程。这可能导致所选的线程并不是你想要的) .
Java does not allow you to specify the thread to be selected ( Java不容许你指定想要选取的线程) .
notifyAll() removes ALL threads from the wait set and places them in the entry set. This allows the threads to decide among themselves who should proceed next ( notifyAll()将等待集中所有的线程移至入口集。这就可以由他们自己决定让谁接着运行) .
notifyAll() is a conservative strategy that works best when multiple threads may be in the wait set ( notifyAll()是较保守的策略,只有在多线程可能在等待集的时候最有效) .
68 04/18/23
Reader Methods with Java Synchronization
public class Database { public Database() { readerCount = 0; dbReading = false; dbWriting = false; }
public synchronized int startRead() { /* see next slides */ }public synchronized int endRead() { /* see next slides */ }public synchronized void startWrite() { /* see next slides */ }
public synchronized void endWrite() { /* see next slides */ }
private int readerCount; private boolean dbReading; private boolean dbWriting;}
69 04/18/23
startRead() Method
public synchronized int startRead() { while (dbWriting == true) {
try {wait();
}catch (InterruptedException e) { }++readerCount;if (readerCount == 1)
dbReading = true;return readerCount;
}
70 04/18/23
endRead() Method
public synchronized int endRead() {
--readerCount if (readerCount == 0) db.notifyAll(); return readerCount; }
71 04/18/23
Writer Methods
public void startWrite() { while (dbReading == true || dbWriting == true)
try {wait();
}catch (InterruptedException e) { }dbWriting = true;
}
public void endWrite() {dbWriting = false;notifyAll();
}
72 04/18/23
Block Synchronization
Blocks of code – rather than entire methods – may be declared as synchronized(宣称同步化的往往是成块的程序代码而不是全部的方法)
This yields a lock scope that is typically smaller than a synchronized method(这将产生出典型的比同步化方法小的锁定范围) .
73 04/18/23
Block Synchronization (cont)
Object mutexLock = new Object();. . .public void someMethod() {// non-critical sectionsynchronized(mutexLock) {// critical section}// non-critical section
}
74 04/18/23
Java Semaphores
Java does not provide a semaphore, but a basic semaphore can be constructed using Java synchronization mechanism ( Java不提供信号量,但是可以用 Java同步机制来建构基本信号量).
75 04/18/23
Semaphore Class
public class Semaphore { public Semaphore() {
value = 0; }
public Semaphore(int v) { value = v;
} public synchronized void P() { /* see next slide */
}public synchronized void V() { /* see next slide */ }
private int value;}
76 04/18/23
P() Operation
public synchronized void P() { while (value <= 0) { try { wait(); } catch (InterruptedException e) { } } value --; }
78 04/18/23
Solaris 2 Synchronization
Solaris 2 Provides( Solaris 2提供):- adaptive mutex(可变互斥量)
- condition variables(环境变量)
- semaphores(信号量)
- reader-writer locks(读–写锁)
Top Related