본문 바로가기

Computer Science/Computer Systems

[Lecture 12] 멀티쓰레딩 VI - Atomicity Violations

#Atomicity Violations

원자성 위반(Atomicity Violations)은 적절한 잠금 규칙을 준수하는 경우에도 발생할 수 있는 동시성 (concurrency) 버그 유형이다(공유 데이터에 액세스하거나 업데이트하는 동안 잠금이 일관되게 유지되는 경우). 보통 Atomic이어야 하는 업데이트가 결합될 때 동일한 잠금의 보호 하에 수행되지 않는 경우 발생한다.

 

원자성 위반 발생 가능 패턴들:

보호용 잠금 장치 획득 (a)
공유 상태에서 정보를 추출 (b)
잠금 해제 보호 (c)
정보를 기반으로 한 행동에 대한 약속 (d)
S'를 보호하는 잠금 장치 획득 (e)
저장된 정보를 기반으로 한 공유 상태 S'에 대한 조치 (f)
S'를 보호하는 잠금 해제 (g)

 

공유 상태로 업데이트되어 b)에서 얻은 정보가 f)에서 최신 정보가 아닐 경우 실패한다. (S는 S'와 같을 수 있다).

#Atomicity Violation Example

char *p = ….; /* shared variable */
pthread_mutex_t lp ; /* protects ‘p’ */
….
int getplen() {
 pthread_mutex_lock (&lp);
 int len = strlen(p);
 pthread_mutex_unlock (&lp);
 return len;
}
…
int nchars = getplen(); // obtain length (safe by itself)
char *copy = malloc(nchars + 1); // commit to allocate memory
pthread_mutex_lock (&lp);
strcpy(copy, p); // copy now possibly out-of-date version
pthread_mutex_unlock (&lp);

#Atomicity Violation Example 2

public synchronized StringBuffer append(StringBuffer sb) {
 // note: StringBuffer.length() is synchronized
 int len = sb.length(); //length 획득
 int newcount = count + len;
 if (newcount > value.length)
 expandCapacity (newcount);
 // StringBuffer.getChars() is synchronized
 sb.getChars(0, len, value, count ); //length가 바뀌었을 시, StringIndexOutOfBoundsException 
 count = newcount;
 return this;
}

#Atomicity Violation Example 3

pthread_mutex_lock (&worker->lock); // protects worker queue
....
 struct listelem *e = list_pop_front (&worker->queue); // grab task from worker queue
 struct future *f = list_entry (e, struct future, elem);
 pthread_mutex_lock (&f->lock); // lock task to update state
 f->state = RUNNING; // mark as running
 // run task
// somewhere in future_get()....
// lock protects state
pthread_mutex_lock (&future->lock);
if (future->state == NEW) {
 // lock containing list
 pthread_mutex_lock (&future->owner->lock);
 list_remove (&future->elem);
 pthread_mutex_unlock (&future->owner->lock);
 f->state = RUNNING;
 // run task
}

첫 번째 코드 부분: 작업자가 대기열을 잠그고 작업을 제거하고 실행을 커밋한다.

두 번째 코드 부분: 참여자가 새 작업을 보고, 작업을 실행하도록 커밋하고, 대기열에서 제거한다.

작업이 두 번 실행된다

원자성 요구 사항: 작업 상태를 변경하고 작업 대기열에 있는 작업을 제거해야 한다.

 

#교착 상태를 피하면서 2개의 잠금을 반대 순서로 획득하는 방법

A.lock()
.… find B
B.lock()
// holding A & B

 

 

retry:
 B.lock()
 …. find A
 if (!A.trylock())
{ B.unlock(); goto retry; }
// holding A & B

#MySql Atomicity Violation

#Typical Atomicity Violation