Synchronization

1.概念

synchronization
processes同步平行處理
容易發生race condition

race condition
多個processes同一時間點存取shared resource,未協調好而導致data inconsientency
ex:
將專屬的設備當成共用設備使用,而造成設備出現異常

…………………….

critical-section
避免race condition的一種方法
一段code,code內的共用資源禁止多個process在裡面執行
結構如下
do{
//entry section 進入critical section的入口區
 critical section
//exit section
 remainder section非critical section的其他程式
}while(1);

critical-section三要素
mutual exclusion(互斥): 只允許1個process在critical-section裡執行
 當process在critical-section存取resource時,其他process無法進入critical-section存取相同資源
progress(進行): 選擇下一個process進入critical-section的時間不可被無限delay
 1.其他process(在remainder section)不能干預其他process進入critical section的決策過程
 2.當多個process要進入時,決定那一個process可先進入critical-section的時間是有限的,(防止deadlock)
bounded waiting(有限等待):
 當process被獲准可進入critical-section後,進入critical-section的等待時間是有限的(防止starvation)
 ex:
 若有n個processes想進入Critical Section,則每個process最多只要等待n-1的時間後就可進入

……………………………………………….

2.解決方案

解決race condition常見的方法有以下
 硬體和軟體
 semaphore
 monitor
….

硬體
開發同步程式較方便
提昇系統效率
常見的有
 disable interrupts
 TestAndSet 一種極小的硬體指令
 CompareAndSwap 一種極小的硬體指令


disable interrupts
適合在單cpu,但較不適合在多cpu系統


TestAndSet
保證mutual exclusion與progress,但是不保證符合bounded waiting
結構大致如下
boolean TestAndSet (Boolean *locked) {
 boolen uv=locked;
 *locked = true;
 return uv;
}
應用在critical section大致如下
do{ //lock是shared variable
 while (TestAndSet(&lock)); //將lock變數的記憶體位置傳入TestAndSet
/*critical section*/
 lock = false; //critical section結束後,則會將lock解除,
/* remainder section */
}while(true)


CompareAndSwap
結構大致如下
int CompareAndSwap(int *v, int exptd, int new){
 int tmp=*v
 if(*v==exptd)*v=new;
 return tmp;
}
應用在critical section大致如下
do{ //lock是shared variable
 while (CompareAndSwap(&lock,0,1));
/*critical section*/
 lock = 0; //critical section結束後,則會將lock解除,
/* remainder section */
}while(true)


軟體
禁止中斷法:使用disable系統呼叫,僅適合在單cpu環境
Dekker’s algorithms
peterson’s algorithms
bakery algorithms:適合解決多個行程同步問題
mutex locks


mutex locks
最簡單的其中一種方法
缺點是會有busy waiting
大致如下
do{
acquire_lock()
/* critical section */
release_lock()
/* remainder section */
}while(1);

busy waiting(忙碌等待)
當process在critical-section時,其他想進入critical-section的process會在entry section一直執行loop來等待
ps:也被稱為spinlock(旋轉鎖),意指cpu會不斷測試該條件是否成立,會浪費cpu cycle

………………

semaphore
常見的synchronization工具,可解決更複雜的synchronization
是一個protected variable
僅提供critical section的同步機制,不保證有mutual exclusion特性,不保證避免deadlock
透過wait()和singal()運算修改protected variable,以達到process synchronization
ps:semaphore常以S表示,wait()常以P()表示,signal()常以V()表示;

semaphore分為
counting semaphore(計數號誌):可製作no busy waiting的mutex locks
binary semaphore(二元號誌): 只有0和1,容易實作,常用在mutex locks


no busy-waiting on counting semaphore
主要透過block()和wakeup()這兩個atomic operate(最小運算)
block():將process改為wait state,也就是將process移到wait queue中
wakeup():將要被wakeup的process從wait queue移到ready queue
ps:也被稱為suspend-lock

no busy-waiting on counting semaphore結構
大致如下
typedef struct{
 int value;
 struct process*list
}semaphore;
wait(semaphore *s){
 s.value–;
 if(s.value <0){
  //add this process to s.list;
  block(); //將process放入waiting queue
 }
}
signal(semaphore *s){
 s.value++;
 if(s.value <=0){
  //remove a process from s.list;
  wakeup(P); //將process從waiting queue移到ready queue
 }
}
應用在critical section的結構如下
semahore mutex; //初始化為1
do{
 wait(mutex);
/* critical section */
 signal(mutex);
/* remainder sectoin */
}while(TRUE);

………………………………..

monitor
以程式語言達到synchronization的機制
保證任何process存取資料是mutex
以blocking和wakeup機制處理process進入critical section

………..

3.synchronization的典型議題

bounded-buffer problem(有限緩衝區問題)
readers and writers problem(讀取寫入問題)
dining-philosophers problem(哲學家進餐問題)

bounded-buffer problem
有n個buffer,每個buffer可保存一個項目,以及多個producer和consumer
程式碼大致如下
initialized: mutex=1,full=0,empty=n
producer process
do{
//produce an item in nextp
wait(empty);
wait(mutex);
//add the item to the buffer
signal(mutex);
signal(full);
}
consumer process
do{
wait(full);
wait(mutex);
//remove an item from the buffer to nextc
signal(mutex);
signal(empty);
//consume the item in nextp
}

readers and writers problem
一個shared data能被同時存取
目標:允許多個reader在相同時間讀取,但僅能一個writer在相同時間存取
程式碼大致如下
initialized: mutex=1,wrt=1,readcount=0
writer process
do{
wait(wrt);
//writing is performed
signal(wrt);
}
reader process
do{
 wait(mutex);
 readcount++;
 if(readcount==1)wait(wrt);
 singal(mutex);
 //reading is performed
 wait(mutex);
 readcount–; 
 if(readcount==0)signal(wrt);
 signal(mutex);
}while(TRUE);