[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

💻 CS/시스템프로그래밍

[시스템프로그래밍] Programs, Processes and Threads

inu 2019. 10. 12. 15:34
반응형

이것은 한낱 대학생이 교수의 수업을 듣고 작성한 개인저장용 복습 문서입니다.

 

그렇지만, 물론 지적과 수정은 환영합니다.


프로그램(program)

정해진 일들을 실행하는 준비된 명령어들의 나열.

c컴파일러는 각각의 소스 파일을 오브젝트 파일로 변환해 준다. 컴파일러는 각각의 오브젝트 파일과 필요한 라이브러리들을 연결하여 실행 가능한 모듈을 만든다.

 

프로세스(process)

실행되고 있는 프로그램의 인스턴스이다.

운영 체제가 커널 자료 구조에 적절한 정보를 추가하고 프로그램 실행을 위한 필요한 메모리 공간을 할당.

프로세스는 주소공간과 적어도 하나의 쓰레드라고 불리는 제어의 흐름을 가지고 있다.

 

프로그램 카운터(PC)

프로세서에 의해 다음으로 실행될 명령어에 대한 정보를 유지한다.

실행 흐름(thread of execution): 프로그램이 실행될 때, 프로그램 카운터가 다음에 실행될 명령어를 결정하면 그 결과로 나타나는 명령어들의 흐름이다. 프로그램 코드가 실행되는 동안 프로그램 카운터로 할당되는 명령어 주소의 흐름이다.

 

cf. context-switch : 실행중인 process 변경. 빠르기 때문에 동시진행처럼 보임.

프로세스 입장에선 정상 흐름으로 진행되지만,

프로세서 입장에선 context-switch가 발생된 것을 알 수 있다.


쓰레드(thread)

프로세스 내에서의 실행 흐름을 나타내는 추상적인 데이터 타입이다.

-쓰레드도 스택, 프로그램 카운터 값, 집합, 상태를 가진다.

-한 프로세스 내에서 여러 쓰레드를 사용함으로써, 적은 오버헤드만으로 병행성을 실현할 수 있다.

-쓰레드가 저장하는 정보의 양이 적어서 Multilple Process보다 유리하다.

-그러나, 한 프로세스 내의 쓰레드들은 동일한 주소 공간을 공유하며 결과적을 프로세스 자원을 공유하기 때문에 추가적인 동기화(additional sychronization)가 필요하게 된다.


프로그램 이미지(program image) 

로딩 후, 프로그램은 실행 가능한 형태로 인접하는 블록들을 차지하게 되는데, 이것을 프로그램 이미지라고 부른다. 프로그램 이미지는 여러 영역을 가지고 있다. 프로그램 텍스트 또는 코드는 아래쪽 주소에 존재한다. 초기화되거나 초기화되지 않은 정적 변수들의 영역도 존재한다. 이 밖의 다른 영역으로는 힙, 스택, 환경변수 등이 있다.

 

main(int argc, char** grgv) : (넘어온 갯수, 각 argument에 저장할 것)

command-line arguments : 명령줄인자 (ls, -l 등)에 대한 정보 보유

eviroment variables : 환경 변수들

heap : 동적할당(malloc)이 일어났을 때 그에 대한 정보 보유

(cf. 동적할당시 free해주지 않으면 함수가 종료되어도 해당 할당된 변수 존재)

stack : 활성 레코드 (함수 실행시 필요한 것들) 보유

uninitialized static data / initialized static data : 정적변수 보유

program text : 소스파일의 명령보유

 

활성화 레코드(activation record) 

프로세스 스택 윗부분에 위치하며, 함수가 호출되는 동안의 실행 컨텍스트를 가지고 있다. 함수가 호출될 때마다 새로운 활성화 레코드가 생성된다. 함수가 리턴될 때 스택에서 제거된다. 활성화 레코드는 리턴 주소, 매개 변수, 상태 정보, 호출될 때의 CPU 레지스터 값들을 가진다. 프로세스를 리턴될 때 활성화 레코드에 저장되어 있던 레지스터 값을 가져온다.


SYNOPSIS box 

필요한 헤더 파일과 함수의 원형을 담고 있는 글상자이다.

 

error

전통적인 UNIX 함수들은 에러시 보통 -1을 리턴하고 에러를 표시하는 errno를 설정한다. 단, 새로운 모든 함수들에 대해 errno를 사용하지 않고 대신에 직접 에러번호를 리턴하도록 하였다.

 

error handling functions

void perror(const char*s) : 현재 errno값에 해당하는 메시지를 출력한다. ( s : 에러 메세지 )

char* strerror(int errnum) : 에러 코드 errnum에 해당하는 시스템 에러 메시지를 가리키는 포인터를 리턴한다. sterror 함수는 errno 값을 바꿀 수도 있다. errno 값을 나중에 다시 사용하고자 한다면 이를 정장해 두었다가 사용해야만 한다. 에러가 발생하지 않아도 사용가능하다.


good model of a function

1. 함수 내부에서 프로그램을 종료시키지 마라. 그 대신 에러값을 리턴한다.

2. 버퍼의 크기에 대하여 불필요한 가정을 하지 마라.

3. 제한을 두어야 할 때, 다른 임의의 상수보다 시스템에 정의된 표준 제한을 사용해라.

4. 입력 매개변수의 값을 바꾸는 것이 정말 의미가 있지 않다면, 입력 매개변수의 값을 변경하지 마라.

5. 자동할당으로 충분하다면, 정적변수나 동적 메모리 할당을 사용하지 마라.

6. 시그널에 의해 인터럽트될 때의 결과를 분석해라.


argument arrays(인자 배열)

문자열들을 가리키는 포인터들의 배열이다. 쉘은 커맨드라인을 토큰들로 나누고, 인자 배열 형태로 프로그램에게 넘겨준다argc는 커맨드라인의 토큰 수이고, argv는 커맨드라인에서 받은 토큰을 가리키는 포인터들의 배열이다.

(int main(int argc, char *argv[]))

 

커맨드라인 'mine -c 10 2.0'에 대한 argv array

 

char *strtok(char* s,char* sep)

실행시 strtok / 파싱할 string 으로 배열이 만들어지고, sep을 기준으로 토큰을 구분한다.

string을 토큰으로 쪼개준다. 내부적으로 정적변수를 사용한다. (각 토큰정보)

재귀적으로 구성해서 반복적으로 리턴, 더이상 나올 것이 없으면 null이 리턴되면서 종료

 

problem of current strtok()

동일한 프로그램 내에서 여러 문자열을 동시에 파싱하기 위해 strtok함수를 호출한다면(strtok를 사용하는 도중 또 strtok를 사용하면. ex 여러 라인의 문장을 라인별로 + 라인을 단어별로), strtok 함수는 파싱 대상 문자열을 위해 하나의 지역 변수만을 사용하기 때문에 이 문자열의 파싱은 서로 방해받고 말 것이다. (여러문장 중 한 문장만 파싱가능)

이와같은 이유로 여러가지 쓰레드의 동시 사용에서도 이런 문제가 발생. 쓰레드끼리는 정적변수 메모리 부분을 공유하기 때문.

 

char* strtok_r(char* s,char* sep,char **lasts)

POSIX가 정의하는 쓰레드 안정성을 보장하는 버전이다.

별도의 저장공간을 파라미터로 추가한다.

lasts 는 다음 파싱이 시작되는 위치를 저장할 장소를 가리키는 포인터로서, 이는 사용자에 의해 제공한다.

즉, 정적변수가 겹치는 일이 없어진다. -> 보통은 다중쓰레드 프로그램 개발시 정적변수 사용을 자제한다.


use of static variables

멀티쓰레드 환경에서 정적변수를 사용하는 것은 각별한 주의가 필요하기 하지만, 정적 변수는 한 함수에 대한 호출 사이의 내부 상태 정보를 담기 위해 사용될 수 있다.

파일 외부에서 그 파일 안에 정의된 자료 구조를 참조하려면 파일에 정의된 접근 함수를 사용해야 한다.

 

Process environment

환경 리스트(environment list)name = value 형식의 문자열을 가리키는 포인터의 배열이다.

name은 환경변수의 이름이고 value는 환경변수의 값이다.

extern char **environ

외부변수 environ은 프로세스가 실행될 때의 프로세스 환경변수를 가리킨다.

 

environment variables

환경변수는 시스템이나 사용자에 특화되어 있는 기본설정값을 프로그램 내에서 사용할 수 있도록 해준다.

char* getenv(const char* name)

getenv 함수는 프로세스의 환경변수가 가지고 있는 값을 얻기 위해 사용된다.

변수가 값을 가지지 않으면 getenv함수는 null을 리턴한다.

 


환경변수 예시

PATH 실행파일을 찾을 위치

 

process termination

normal termination

-main함수로부터의 리턴

-main 함수로부터 암묵적으로 리턴

 

exit,_Exit,_exit함수 호출

exit()

사용자가 정의한 exit핸들러들을 호출한다. exit핸들러는 atexit함수를 사용하여 등록할 수 있다.

이 때 호출되는 순서는, atexit함수를 사용하여 등록한 순서의 역순이다.

int atexit(void (*func)(void))

 

abnormal termination

abort함수를 호출하거나 종료를 야기하는 시그널을 처리함으로써 비정상적으로 종료될 수 있다.

코어덤프를 생성해낼 수 있다.

반응형