학부 내용 정리/[ 2-1 ] 운영체제

[ OS ] Concurrency and Thread

haena02 2022. 6. 11. 18:09
반응형

 

1. Multi-threaded program

 

단일 스레스는 프로세스와 비슷하게 각 스레스 자체 PC와 레지스터, 스레드만의 스택을 가지고 있다. 하지만 멀티 스레드는 프로세스와 다르다.

 

- 동일한 주소공간을 공유하여 같은 데이터에 접근할 수 있음

- 동일한 주소공간을 갖고 있어 페이지 테이블을 전환할 필요 없음 (context switch 필요 없음)

* context switch는 프로세스가 바뀔 때만 일어남

 

스레드는 TCB(Thread Control Block)으로 관리된다.

스레드는 Heap 영역과 Program Code(read only) 부분은 공유하고 stack 영역은 스레드별로 가지고 있다.

 

1.1 스레드의 장점

 

1) 병렬성을 증가시킬 수 있다

- CPU의 개수가 계속 늘어나고 있는데 이때 각 CPU가 병렬성을 가지고 움직일 수 있게 해준다.

 

2) 매우 느린 I/O 를 사용할 때 CPU 스케줄러는 스레드 전환을 시켜줄 수 있다

 

-> 최신 서버 기반 응용 프로그램에 많이 스레드를 이용한다 (ex. 웹서버, 데이터베이스 관리 시스템)

 

1.2 스레드 사용하기

 

void *mythread(void *arg)  // 리턴값과 인자값은 꼭 void * 으로
{ 
	printf("%s\n", (char *) arg); 
	return NULL; 
} 


int main(int argc, char *argv[]) 
{ 
	pthread_t p1, p2; 
	int rc; 
    //스레드 생성 (pthread_t 주소, NULL, 스레스에서 실행될 함수, 함수에 넣을 인자)
	rc = pthread_create(&p1, NULL, mythread, "A"); assert(rc == 0); 
	rc = pthread_create(&p2, NULL, mythread, "B"); assert(rc == 0); 
	// 스레드 종료될 때까지 기다림
	rc = pthread_join(p1, NULL); assert(rc == 0); 
	rc = pthread_join(p2, NULL); assert(rc == 0); 
	return 0; 
}

 

 

1.3 multi thread 실행 예시 (CPU 코어 하나)

 

 

두가지 경우의 상황이 적혀있는 표이다.

첫번째 상황은 스레드 두개가 생성이 되고 main은 T1을 wait 하며 block 상태로 있다가 T1 이 실행되고 종료하니 T2를  wait 하며 block 상태로 있다가 종료하는 상황이다.

두번째 상황은 T1 스레드가 생성되자마자 실행되고 T2도 생성되자마자 실행한다, 그러고 나서 main이 wait 하려는데 이미 종료된 상태여서 block 상태로 가지 않고 바로 종료된 상황이다.

 

1.4 shared data

 

static volatile int counter = 0;  // shared data
void * mythread(void *arg) 
{ 
	int i; 
	for (i = 0; i < 1e7; i++) { 
		counter = counter + 1;  // 1씩 증가
	} 
	printf("%s: done\n", (char *) arg); 
	return NULL; 
} 

int main(int argc, char *argv[]) 
{ 
	pthread_t p1, p2; 
	printf("main: begin (counter = %d)\n", counter); 
    
	pthread_create(&p1, NULL, mythread, “A”); 
	pthread_create(&p2, NULL, mythread, "B"); 
	pthread_join(p1, NULL); 
	pthread_join(p2, NULL); 
    
	printf("main: done with both (counter = %d)\n", counter); 
	return 0; 
}

 

위 코드는 바른결과가 나오지 않는다 이는 race condition 이 일어났기 때문이라고 할 수 있다.

 

2. Race Condition

 

counter = counter + 1;

 

위 코드를 실행하기 위해 컴퓨터는 어셈블리어로 아래와같은 일을 수행하다.

 

100 mov 0x8049a1c, %eax       //메모리 주소에서 counter 값을 가져와서 eax 레지스터에 저장 

105 add $0x1, %eax                 // eax 레지스터에 있는 값에 1 더하기 

108 mov %eax, 0x8049a1c      // 다시 counter 에 넣어주기

 

 

아래 사진은 race condition 이 일어나는 상황이다.

 

 

T1 에서 counter 값을 가져와서 1을 더했다. 근데 다시 counter 에 더한값을 넣지 못하고 context switch 가 일어났다. 그래서 T2는 더해진 값이 아닌 이 전 값을 받게 되고 거기에 1을 더해서 counter에 넣게된다. 이 때 또 context switch가 일어나게 되고 T1은 51을 51로 바꾼다.

 

2.1 Critical section

 

critical section : 공유자원에 접근하는 코드를 의미한다. 둘 이상의 스레드로 동시에 실행하면 안된다.

mutual exclusion : 한 스레드가 critical section 내에서 실행중인 경우 다른 스레드가 실행 중지된다.

atomic : 방해받지 않는다. 실행되지 않거나 실행완료되거나 두 상태만 가능

 

-> 동기화를 하기 위해서 atomic 지침을 지원해주면 된다.(ex. mutex, condition variable)

 

3. Atomicity

3.1 Mutex

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // static 선언
int rc = pthread_mutex_init(&lock, NULL)  // dynamic 선언
... 
pthread_mutex_lock(&lock);   // 잠구고 들어가기
counter = counter + 1; // critical section 
pthread_mutex_unlock(&lock);   // 나오며 열기

pthread mutex destroy();  // 제거

mutex 함수의 기본적인 사용법은 위와 같다. 위의 함수를 변형한 함수도 존재한다.

int pthread_mutex_trylock(pthread_mutex_t *m)  // lock 시도 후 안되면 return
int pthread_mutex_timedlock(pthread_mutex_t *m,struct timespec *abs_timeout)
// lock 시도 후 안되면 계속 시도 or 정해진 시간만큼 시도

 

 

3.2 Condition variable

 

이는 다른 스레드가 수행되기를 기다릴 때 사용되며 스레드간에 신호가 발생해야할 때 유용하다. 아래 두 함수 중 하나를 사용하면 되고 뮤텍스 잠금상태를 유지해야 사용할 수 있다.

 

int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex) 
int pthread_cond_signal(pthread_cond_t *cond)

 conditon variable이 없다면 while()문으로 상태가 변할 때까지 계속 기다려야하는데 이는 메모리낭비가 심하다. 

사용되는 예시를 보겠다

//T1

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // mutex 선언
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;   // condition variable 선언
pthread_mutex_lock(&lock); 
while (ready == 0) 
	pthread_cond_wait(&cond, &lock);   //잠듬. 깨고나면 ready가 1이됨. condition variable와 mutex 인자로 넘김
pthread_mutex_unlock(&lock);


//T2

Pthread_mutex_lock(&lock); 
ready = 1; 
Pthread_cond_signal(&cond);  //cond 를 가진애를 깨움
Pthread_mutex_unlock(&lock);

 

 

반응형

'학부 내용 정리 > [ 2-1 ] 운영체제' 카테고리의 다른 글

[ OS ] Lock-based Concurrent Data Structures  (0) 2022.06.12
[ OS ] Locks_slides  (0) 2022.06.12
[ OS ] Translation-Lookaside Buffer  (0) 2022.04.19
[ OS ] Paging  (0) 2022.04.18
[ OS ] Segmentation  (0) 2022.04.18