시험 정리용... 내용 매우 알아보기 힘들 것임...
멀티프로세스의 단점
context switching
오버헤드가 매우 큼=> 스레드
나옴
장점
프로세스는 데이터, 스택, 힙 영역을 별도로 유지
스레드는 스택 영역만 분리!!
스레드는 스택만 분리고 힙,데이터 영역은 공유한다
스레드끼리 context switching 오버헤드가 낮다
데이터 영역 공유 덕분에 data change가 쉽다
그래서..
프로세스: OS 관점
에서 별도의 실행흐름을 구성
쓰레드: 프로세스 관점
에서 별도의 실행흐름을 구성
OS는 여러 프로세스를 지니고 프로세스는 여러 쓰레드를 지닌다
스레드는 스레드만의 main을 정의해야함.
그리고 이를 형성해 줄 것을 요청해야함.
#include <pthrad.h>
int pthread_create(pthread_t *restrict thread, const pthread_attr_t * restrict attr, void * (*start_routine)(void*),void* restring arg);
스레드가 생성된 main함수가 종료되면 프로세스 전체가 소멸되어 해당 스레드도 죽는다!
그래서 따로 함수를 이용해 확인을 해야함!!
#include <pthread.h>
int pthread_join(pthread_t thread, void **status);
=> 즉, 전달되는 ID의 스레드가 종료될 때 까지 이 함수를 호출한 프로세스(스레드)를 대기상태로
join을 호출하고 난 이후! 해당 프로세스는 해당 스레드가 끝날 때까지 기다림!!
둘 이상의 쓰레드가 동시에 실행하면 문제를 일으키는 함수
쓰레드에 안전한 함수도 임계영역이 존재 할 수도
엥?
쓰레드 관련 코드가 있으면 D_REENTRANT를 컴파일할때 삽입
두 쓰레드가 하나의 전역 변수에 접근을 하면??
예상 결과와 실행 결과가 다름!!
왜??
스레드들은 CPU를 RR 방식으로 사용하니 동시접근이 될까??
동시 접근이 아니라.. 값에 접근할 때 동기화가 안된 값을 가져가는 문제가 생길 수 있음..
연산을 진행한 값을 다른 스레드가 사용해야하는데, 연산이 진행되지 않은 값을 가져가버리는 경우...
동기화
가 필요!!
함수 내에 둘 이상의 스레드가 동시 실행하면 문제를 일으키는 코드 블록
동기화가 필요한 상황
동기화는 운영체제의 종속적이라 다른 운영체제는 다른 접근 방법을 사용해야한다
생성, 소멸
#include <pthread.h>
int pthread_mutex_init(*mutex,*attr);
int pthread_mutex_destroy(*mutex);
뮤텍스의 생성을 위해선 뮤텍스형 변수가 하나 선언되어야함.
pthread_mutex_t mutex;
잠금, 품
$include <pthread.h>
int pthread_mutex_lock(pthread_mutext_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
lock과 unlock을 이용해 임계영역의 시작과 끝을 감싸!
생성, 소멸
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
lock unlock
#include <semaphore.h>
int sem_post(sem_t *sem);
int sem_wait(sem_t *sem);
세마포어 활용법
init을 호출하면 세마포어 오브젝트
가 만들어짐.
sem_post가 호출되면 세마포어 값 1 증가
sem_wait이 호출되면 세마포어 값 1 감소
세마포어값은 0
보다 작아질 수 없음!!!
그래서 값이 0인 세마포어에 sem_wait을 호출하면??
블로킹 상태
가 됨이를 이용해 임계영역을 동기화
sem_wait(&sem) // 세마포어 값 0
//임계
//끝
sem_post(&sem) //세마포어 값 1
이렇게 되면, sem_post를 호출 전에는 다른 쓰레드에 의해 임계영역의 진입이 허용 안됨.
코드를 보고 이해를 하자!! 필요한 것만 구성
int main(int argc,char* argv[]){
pthread_t id_t1,id_t2;
sem_init(&sem_one,0,0);
sem_init(&sem_two,0,1);
pthread_create(&id_t1,NULL,read,NULL);
pthread_create(&id_t2,NULL,accu,NULL);
}
void* read(void* arg){
int i;
for(i=0;i<5;i++){
fputs("Input num: ",stdout);
sem_wait(&sem_two);
scanf("%d",&num);
sem_post(&sem_one);
}
return NULL;
}
void* accu(void* arg){
int sum=0,i;
for(i=0;i<5;i++){
sem_wait(&sem_one);
sum+=num;
sem_post(&sem_two);
}
printf("Result: %d \n",sum);
return NULL;
}
값이 0일때 wait이면 블로킹을 이용!!
sem_one은 세마포어 값 0으로 시작, sem_two는 1로 시작.
스레드를 생성하고 실행
accu할때 값이 입력도 안됐는데 가져가는 경우를 막기 위해 초기 sem_one을 0으로 설정
사용자가 값을 입력해 sem_one값이 1로 변해 accu가 값을 가져감, 이후 two를 1로 post해 read
#include <pthread.h>
int pthread_detach(pthread_t thread);
clnt_cnt와 clnt_socks에 접근하는 코드는 임계영역을 구성
while(1){
clnt_adr_sz =sizeof(clnt_adr);
clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_sz);
pthread_mutex_lock(&mutx);
clnt_socks[clnt_cnt++]=clnt_sock;
pthread_mutex_unlock(&mutx);
pthread_create(&t_id,NULL,handle_clnt,(void*)&clnt_sock);
pthread_detach(t_id);
printf("Connected client IP: %s \n",inet_ntoa(clnt_adr.sin_addr));
}
void* handle_clnt(void* arg){
int clnt_sock = *((int*)arg);
int str_len = 0,i;
char msg[BUF_SIZE];
while((str_len=read(clnt_sock,msg,sizeof(msg)))!=0)
send_msg(msg,str_len);
pthread_mutex_lock(&mutx);
for(i=0;i<clnt_cnt;i++){
if(clnt_sock==clnt_socks[i]){
while(i++<clnt_cnt-1){
while(i++<clnt_cnt-1)
clnt_socks[i]=clnt_socks[i+1];
break;
}
}
}
clnt_cnt--;
pthread_mutex_unlock(&mutx);
close(clnt_sock);
return NULL;
}
void send_msg(char* msg,int len){
int i;
pthread_mutex_lock(&mutx);
for(i=0;i<clnt_cnt;i++)
write(clnt_socks[i],msg,len);
pthread_mutex_unlock(&mutx);
}