Computer Science/시스템 프로그래밍

시스템 프로그래밍 chapter 02.

만능 엔터테이너 2024. 10. 8. 16:05
728x90
반응형
SMALL

프로그램, 프로세스, 스레드

목표는 다음과 같습니다:

  • 프로그램, 프로세스, 스레드에 대해 배우기
  • 메모리 할당 및 조작 실험
  • 정적 객체의 의미 탐구
  • 환경 변수를 문맥에 맞게 사용하기
  • 프로그램 구조와 레이아웃 이해

Program (프로그램)

- 정의된 작업을 수행하기 위해 준비된 일련의 명령어, 컴파일러가 각 소스 파일을 오브젝트 파일로 변환하고, 필요한 라이브러리와 함께 실행 가능한 모듈을 생성

Process (프로세스)

- 프로세스 실행 중인 프로그램의 인스턴스를 말하며 바로 실행되는 것이 아닌 Ready Queue에서 대기하다가 os가 실행할 프로세스를 선택하면 레디 큐에서 나와 cpu와 함께 실행됨, 프로세스는 주소 공간을 가지며 적어도 1개의 제어 흐름을 가진 스레드가 존재함
운영체제가 적절한 정보(프로세스 ID, 상태 등)를 커널 데이터 구조에 추가하여 프로그램 코드를 실행하는 데 필요한 리소스를 할당하면 프로세스로 변환됨

Threads and thread of execution (스레드와 실행 흐름)

- Program Counter(프로그램 카운터) : 다음에 실행될 프로세스 명령어를 결정하는 역할, 프로그램 카운터 안에는 매번 실행할 주소가 들어 있어서, 프로그램이 끝나면 다음 프로그램이 차례대로 실행됩니다.

- A thread of execution (실행 흐름의 스레드) : 명령어의 흐름, 프로그램 카운터에 할당된 명령어 주소의 순서 표현

 

중간 중간에 문맥 전환(context switch) 명령어가 발생하여 반복적으로 조금씩 실행되며, 마치 동시에(concurrent) 실행되는 것처럼 보입니다. 이는 멀티 프로그래밍타임 쉐어링을 통해 이루어집니다.
 

Multiple threads (멀티 스레드)

- Thread (스레드) : 프로세스 내 실행 흐름을 나타내는 추상 데이터 타입으로 각 스레드는 독립적으로 실행 스택(stack),프로그램 카운터(program counter), 레지스터(register), 집합 및 상태(state)를 가짐
 
다중 프로세스 vs 다중 스레드다중 스레드는 문맥 전환(context switch)를 피하고 코드와 데이터를 공유가능하고 스레드의 정보가 프로세스보다 더 적기에 멀티 스레드가 더 좋음(실행이 빠름) 또한, 낮은 오버헤드 병렬성 제공 및 동일한 프로세스 주소 공간에 위치하고 프로세스 리소스를 공유하기에 추가적인 동기화(스레드간 동기화)가 필요함
=> 멀티 스레드를 사용할 때, 공유 자원을 사용하는 문제점이 발생 가능

A program image (프로그램 이미지)

- 프로그램 실행 파일이 점유하는 논리 메모리의 연속적인 블록, 여러 구분된 영역으로 나뉘며 프로그램 텍스트 저순위 메모리에 표시되고 초기화된 정적 변수와 초기화되지 않은 정적 변수는 각자의 영역을 가지고, 프로그램 이미지 내부스택과 힙 영역이 존재합니다.
- 프로그램 텍스트 및 초기화 or 비초기화된 변수들이 저장되는 메모리 공간과 스택, 힙 메모리 공간이 프로그램 이미지 내부에 존재함

  • 높은 주소(high address)에서부터 낮은 주소(low address)로 내려가는 구조
  • command-line argumentsenvironment variables가장 상단에 위치하며, argc, argv와 같은 환경 변수가 포함됩니다.
  • stack (스택): 함수 호출 시마다 activation record (활성화 기록)가 저장됩니다. 이는 함수의 반환 주소, 파라미터, 저장된 레지스터, 자동 변수 등을 포함하며, 함수 실행에 필요한 메모리를 담습니다. 함수 호출이 끝나면 이 기록이 삭제됩니다. 함수 호출 시 스택이 늘어나고, 함수가 끝나면 스택이 줄어듭니다.

 

  • heap (힙): malloc(), alloc(), calloc()와 같은 동적 메모리 할당 함수에 의해 메모리가 할당됩니다. 이 메모리는 수동으로 해제해야 하며, free() 함수로 해제해야 합니다. 힙은 동적으로 할당된 메모리를 유지하는 공간입니다.
  • static data (정적 데이터): 초기화되지 않은 정적 변수uninitialized static data에 저장됩니다. 초기화된 정적 변수initialized static data에 저장됩니다.
  • program text (프로그램 텍스트): 프로그램 코드 자체는 메모리의 가장 하단에 위치합니다.

heap 공간에 할당된 메모리는 사용자가 free()를 통해 수동으로 해제해야 합니다.
 

Activation record (활성화 기록)

- 함수 호출 중 실행 컨텍스트를 저장하기 위해 프로세스 스택의 최상단에 할당된 메모리 블록, 각 함수 호출은 새로운 활성화 기록을 생성합니다. 활성화 기록에는 반환 주소, 파라미터, 상태 정보, CPU 레지스터 값의 복사본, 자동 변수 등이 포함

Library function calls( 라이브러리 함수 호출)

- SYNOPSIS box (요약 상자) : 함수 사양의 간략한 버전을 제공하고 필요한 헤더 파일과 함수의 프로토타입을 제공
- Error (오류) : 전통적인 UNIX 함수는 보통 -1을 반환하거나 (때로 null을 반환) errno를 설정하여 오류를 표시
 But, 새로운 함수는 errno를 사용하지 않고 함수 반환 값으로 오류 번호(에러 코드)를 직접 반환

Error handling functions (오류 처리 함수)

- void perror(const char *s) : string값을 파라미터로 받아 현재의 errno값에 해당하는 오류 메시지를 출력, #include <stdio.h>를 포함
- char strerror(int errnum) : errnum에 해당하는 오류 메시지에 대한 포인터를 반환하고,
#include <string.h>를 포함 /  errno를 변경가능하기에 errno를 다시 사용한다면 다른변수로 저장하고 복구해야 합니다. 

Good model of a function (함수의 좋은 설계 모델)

- 함수에서 바로 종료하지 말고 오류 값을 반환하고 버퍼 크기에 대한 불필요한 가정 하지 말 것

- 임의의 상수 대신 표준 시스템 정의 한계를 사용하고 변경이 타당한 경우를 제외하고 입력 파라미터 값을 변경하지 말 것

- 자동 할당으로 충분하면 정적 변수 및 동적 메모리 할당을 피하고 malloc 계열 함수 호출을 모두 분석할 것

An argument array (인수 배열)

 
문자열에 대한 포인터 배열입니다.
셸(Shell)이 명령줄을 토큰으로 구문 분석하고, 그 결과를 프로그램에 인수 배열의 형태로 전달합니다.
 
 


Thread-safe strtok()

 
- strtok() 함수의 문제점 : 정적 변수를 사용하기 때문에, 여러 스레드에서 동시에 실행하면 서로 간섭하여 문제가 발생할 수 있습니다. 예를 들어, 동일한 프로그램 내에서 서로 다른 문자열을 동시에 구문 분석하려고 하면, 구문 분석이 꼬여 버릴 수 있습니다. 이는 스레드에서 안전하지 않습니다.
 
char* strtok_r(char* s, const char* sep, char **lasts)
- strtok_r() 함수가 그 해결책으로 나오게 되었고, 이 함수는 스레드 안전 함수다중 스레드 환경에서도 문제 없이 동작함, strtok_r()은 lasts라는 추가 매개변수를 사용하여 각 스레드에서 문자열의 현재 구문 분석 상태를 저장 가능합니다.
따라서, 여러 스레드가 동시에 실행될 가능성이 있거나 안정성을 중요시하는 프로그램에서는 strtok_r()함수가 더 좋음
 
strtok(input string으로 전체 단락, 라인단위로 토큰분류) ㅡ> strtok(1개의 라인, word단위로 토큰 분류)

Use of static variables (정적 변수의 사용)

- 정적 변수는 함수 호출 간 내부 상태 정보 유지하는데 유용하지만, 다중 스레드에서는 사용할 때 주의가 필요
- 정적 변수와 함수는 내부 연결성(internal linkage)을 가지고 있어 해당 파일 외부에서 직접 접근이 불가능
- 정적 변수는 접근 함수(access functions)를 통해 외부에서 접근이 가능
 

Process environment (환경 변수) - env를 터미널에 입력하여 확인

- 환경 목록 : name = value 형식의 문자열에 대한 포인터 배열을 말하며, name 환경 변수의 이름, value 이름과 관련된 문자열 값
- extern char environ (ISO C) : 프로세스가 실행될 때 환경 목록을 가리키는 포인터
- 환경 변수 : 프로그램 내부 시스템 및 사용자 특화 정보를 사용하여 기본값 제공 메커니즘 / 예) 경로, 홈 디렉터리
char* getenv(const char* name): 특정 환경 변수가 값을 가지고 있는지 확인하는 함수, 만약 변수가 값이 없으면 NULL 반환

Process termination (프로세스 종료)

- 정상 종료 (Normal termination)

  • main 함수에서 반환 : main 함수에서 값을 반환하여 프로그램이 정상적으로 종료
  • 암시적 반환 : 명시적으로 반환하지 않아도 main함수가 끝나면 자동으로 반환
  • exit, _Exit,_exit 함수 호출 : 종료 상태 값을 인수로 받아 프로그램 종료, 성공적으로 종료되면 0을 반환

- exit() 함수 :
 사용자 정의 종료 핸들러를 호출하여 atexit()함수를 통해 등록하여 등록된 순서의 역순으로 호출됨

- int atexit(void (*func)(void)):
종료 시 실행할 함수를 등록함

- 비정상 종료 (Abnormak termination) :

  • abort 함수: 프로그램을 강제로 종료
  • 종료를 유발하는 시그널 : 특정 신호에 의해 프로그램이 종료
  • 코어 덤프 생성 가능 : 비정상 종료 시 프로그램 상태를 기록한 코어 덤프가 생성 될 수 있음

 

728x90
반응형
LIST