-
최적화컴파일, IPC, 세마포어, 스핀락시스템프로그래밍 - 리눅스 2022. 12. 18. 13:36728x90반응형
최적화 컴파일
최적화 컴파일 gcc -O test.c
성능를 최적화->코드 사이즈도 적당히 줄이고 성능도 적당히 올리는것.
값을 메모리에 넣지않고 레지스터에 넣음으로써 성능을 최적화 한다.
gcc -O2 test.c
성능을 극대화
코드 크기 신경안쓰고 성능만 개빠르게
최적화컴파일
컴파일을 최적화하여 진행하게 되면
C문법을 엄격히 준수해야한다.
컴파일에서 최적화 하기 위해 데드코드 엘리미네이션과 레지스터활용을 하기때문에 원하는 값이 안나올수 있기 때문이다
ex) int a=0;
(short*)(&a)[1] |= 1;
(short*)(&a)[1] |= 1;
이렇게 하게 되면 그냥 gcc를 돌릴때는 결과가 맞게 출력이 되지만
최적화 컴파일을 하게 되면 결과가 0이 나올것이다.
최적화를 통해 사용되는 레지스터는 강제형전환에 의한 C언어 표준규격상 지원하지 않는 방법으로 메모리에 접근하기 때문에 명확이 알고 사용하지 않는 경우에는 구성에 따라 이런 문제를 발생시킬 수도 있다.
그래서 gcc -O2 -Wstrict-aliasing=2 test.c
라는 strict-aliasing=2라는 옵션을 함께 사용해서 컴파일 해야한다.
최적화를 이용한 컴파일시에는 경고하는 메세지를 무시해서는 안된다.IPC(Inter Process Communication)
IPC(Inter Process Communication) IPC를 사용하는 이유는 무엇인가?
A프로세스와 B프로세스가 각각 존재한다 가정했을 때
A와 B가 서로가 가지고 있는 정보를 공유할 수 없기 때문이다.
우선 프로세스의 기본적인 개념을 생각해보면
프로세스는 각자 자신의 자신만의 고유한 4GB 가상 메모리 공간을 가지고 있다.
이 상태에서 서로 독립적인 공간을 가지고 있다보니
정보를 공유할 수 없었다
(저번에 간략한 포인터 예를 통해서도 확인 했었다)
그러나 IPC를 사용하면 Pipe 나,
Semaphore, Message Queue, Shared Memory등은
프로세스 간에 정보를 공유할 수 있도록 만들어 준다.
원리는 메모리 상에 특정한 공간을 잡아놓고
해당 공간에 접근할 수 있는 권한을 만든다.
그리고 그 공간에 서로
공유하고자 하는 정보를 집어넣는 것이다.
그러면 권한을 가지고 있는 녀석들끼리
메모리에 접근해서 값을 읽거나 쓰는 작업을 수행할 수 있을 것이다.스핀락(Spinlock)
스핀락(Spinlock)
상당히 정확한 답변입니다. 첨언하면 스핀락을 잘못 사용하면 CPU 사용률 100%를 만드는 상황이 발생하므로 주의 하여야합니다. 스핀락은 기본적으로 무한 for 루프를 돌면서 lock을 기다리므로 하나의 쓰레드가 lock을 오랫동안 가지고 있다면, 다른 blocking된 쓰레드는 busy waiting을 하므로 CPU를 쓸데없이 낭비하게 됩니다.
스핀락을 잘 사용하면 context switch를 줄여 효율을 높일 수 있습니다. 그리고 윈도우즈의 스핀락은 그다지 효율적이지 않습니다. 무한 루프를 돌기 보다는 일정 시간 lock을 얻을 수 없다면 잠시 sleep하는 back off 알고리즘을 사용하는 것이 훨씬 좋습니다.세마포어(semaphore), 뮤텍스(mutex)
세마포어(semaphore), 뮤텍스(mutex) 세마포어는
locking 이 걸려있는 critical section 을 쓰기위한 프로세서는 wait 상태가 되고
critical section 이 unlocking 이 됬을때 wait 하고있는 프로세서에게 신호를 보내서 사용하게 하는 방식
[ S 라는 변수를 갖고 있으며, P(S) 로 들어가도 되는지 체크하고 V(S) 로 S에 대한 연산을 한다. ]
P(S)
{
while (S <= 0)
continue;
S--;
}
V(S)
{
S++;
}
이런 형태는 프로세스가 busy wait(아무것도 안하고 CPU를 잡고있다) 에 놓이게 된다. (이게 스핀락인가?)
또한 다른 프로세스들간에는 사용하기 힘들다는 문제점도 가진다. 반면 세마포어는
busy wait 상태에 놓이지 않는다.
커널에서 관리되기 때문에 다른 프로세스들간에도 사용할 수 있다.
는 장점을 가진다.
세마포어를 제어하기 위해서는 P함수와 V함수를 사용해야 하는데, 이 두개의 함수는 독립적이다. 때문에 잘못사용하게 될경우 deadlock에 빠질 수 있다.deadlock(교착상태는 나중에 알아볼것임)
뮤텍스는
카운트가 1인 세마포어 ( 하나의 프로세서만이 활용가능한 critical section 일 때 세마포어 형식으로 메모리를 공유하는 방법 )크리티컬 섹션(critical section)
크리티컬 섹션(critical section) critical section 은
여러 프로세스들이 하나의 공간에 접근해서
데이터의 쓰기 및 읽기 등이
꼬이게 될 가능성이 있는 공간을 뜻한다.세마포어(semaphore) vs 스핀락(spinlock)
세마포어(semaphore) vs 스핀락(spinlock) Spinlock
이 녀석은 Polling 메커니즘을 따르는 Lock 메커니즘이다.
기본적으로 시스템 프로그래밍을 하게 되면
나오는 구도가 아래와 같다.
Semaphore(Mutex) vs Spinlock
위와 같은 구도로 나오는데 Spinlock은 도대체 뭘까?
여기서도 굉장히 흥미로운 주제가 기다리고 있다.
아무튼 Semaphore와 Spinlock은 누가 더 좋을까?
경우에 따라서 둘 다 좋다!
Semaphore의 경우 Semaphore에 속해서 구동하게 되는 작업이 방대할 경우
굉장한 이득을 얻을 수 있다.
반면 Spinlock의 경우 작업의 양이 비교적 간단하면 간단할 수록 굉장한 이득을 얻게 된다.
Semaphore나 Spinlock 모두 이러한 특징이 나타나게 되는 원인은
결국 Context Switching이다.
(COntext Switching은 프로세스정보 메모리정보 레지스터정보를 저장해야 된다.)
만약 덧셈이라고 생각하면 Spinlock으로 계속 CPU를 잡고 있는게 이득이다. 하지만 복잡한 연산이라면 프로세서 하나가 계속 CPU를 잡고 있으면 불리하게 될 것이다.
그래서 세마포어 구조로 설계되어야 한다.문제는 Semaphore는
단순히 이러한 용도로 개발된 것이 아니라는 것이다.
Semaphore가 나오게 되면 System에서는 반드시
같이 따라서 나오게 되는 것이 Spinlock 이며
또한 Critical Section 이라는 영역이 같이 나온다.
여러 개의 프로세스가 동시 다발적으로 구동된다고 할 때
특정한 메모리에 여러 프로세스가 동시에 접근해서
값을 읽거나 쓴다고 생각해보자!
그러면 분명히 값을 제대로 읽지 못한 프로세스
혹은 값을 제대로 쓰지 못한 프로세스 등
다양한 문제가 발생하게 될 것이다.
참고로 위에 적어놓은 원리는 Message Queue에만 국한됨
Semaphore 관점에서는 공유하게 되는 공간이
위의 원리와 같은 공간일 수도 있고
전역 변수와 같은 정보를 공유하는 Thread일 수도 있음
중요한것은 어쨋든 정보가 공유가 가능할 경우
읽기 및 쓰기가 꼬여 문제가 발생할 수 있는
그 영역 자체를 Critical Section이라 한다는 것임
그렇다면 도대체 왜? 값이 꼬일까?
(그림)
이론적으로 파악을 해보자면
A프로세스에서 + 연산을 하고 있는 도중에
Context Switching이 발생하는 것이다.
그래서 B로 제어권이 넘어갔다고 하자!
B는 -연산을 하고 있는 것이다.
예로 현재 공유 정보가 1이었다고 해보자!
A - B - A - B를 진행했다면 값은 1로 유지되야 한다.
그러나 Critical Section 문제가 터지게 되면
A가 연산 도중에 B로가서 연산이 완료되고
A가 다시 연산하면 0이 될 것이며
다시 위와 같은 상황이 반복되면 -1이 될 것이다.
즉, 원하는 결과인 1 아닌 -1이 되버리는 것이다.
이런 상황을 막기 위해 등장한 개념이 바로 Semaphore이다.
/////////////////
모든 프로세스는 고유의 4GB를 갖는다.
Thread와 Process는 모두 task_struct이다.
Thread는 데이터영역을 공유한다. (실제 스택영역을 제외하고는 모두 공유된다)
공유영역을 Critical Section이라고 한다.
공유영역을 다른 프로세스나 쓰레드가 쓰고있을때
다른 프로세스가 접근을 못하게 하는것을
Mutex 구조 이자 Semaphore 구조
차이점은
Mutex는 단일
Semaphore는 여러 프로세스를 동시에 돌릴수 있다.
Semaphore는 멀티
//////////////////////////////////////////////
//////////////////////////////
Shared Memory
gcc -o send send.c shmlib.c
gcc -o recv recv.c shmlib.c
터미널을 2개 띄우도록 한다.
그리고 한쪽에서 아래와 같이!
./send
다른한쪽에서 아래와 같이! 하는데 우선 send만 해둔다.
./recv
그리고 ./send 를 실행시킨 쪽에서 엔터키 한번입력
이후에 ./recv 를 실행시킨 쪽에서 엔터키 한번입력
그러면 send쪽의 정보가 recv에 공유될 것이다.
728x90반응형'시스템프로그래밍 - 리눅스' 카테고리의 다른 글
openMPI(슈퍼컴퓨팅 라이브러리) 설치 및 예제(예제수정중) (0) 2022.12.20 cow 아키텍처, 좀비프로세서(defunct), 시그널(signal), core dump, 실행파일포맷(ELF 포맷) (0) 2022.12.19 pipe통신, Blocking vs Non-Blocking, Polling, Interrupt(부록 GPI디버깅) (0) 2022.12.17 Context Switching, Run Queue, Wait Queue, Scheduling, Multi-Tasking (0) 2022.12.16 usleep(), signal(), waitpid(), deamon프로세서, Pipeline Architecture (0) 2022.12.15