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

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

Tag
Computer Science Engineering
System Programming

프로그램이 어떻게 프로세스가 되는가?

  • 프로그램
    • 스태틱한 객체로, instruction들의 나열
    • instruction의 시퀀스로, 정의된 일들을 실행하기 위함
    • 컴파일을 통해 object file을 생성. 라이브러리를 사용하고 있다면 링크 과정까지 포함 ⇒ 실행 가능한 파일 *.c ⇒ *.out
  • 프로세스
    • 하드디스크에 있던 프로그램의 정보들이 메모리에 로드가 되어 실행이 되는 것
    • OS가 pid, state 등과 같은 Information이 메모리에 로드 / 메모리 공간 할당
    • 바로 실행되는 것이 아닌 ready queue에 대기하고 있다가, CPU로 실행 된다.
    • 프로세스 내부에는 실행 흐름을 담당하는 객체가 같이 실행되는데, 이를 thread 라고 한다.
    •  

Threads and thread of execution

  • Program counter
    • 다음에 실행할 instruction의 주소 정보가 들어가 있다.
  • thread의 실행 흐름
    • instruction의 stream
    • Program counter에 할당된 다음 실행될 instruction의 주소값을 통해 표현된다.
 

Thread of Execution example

1번 프로세스가 실행할 루프 안의 statements가 245, 246, 247
표현 방식: statement(pid)
→ Result: 245(1), 246(1), 247(1), 245(1), 246(1), 247(1)
 
1번 프로세스는 루프 안의 statements 245, 246, 247 / 2번 프로세스는 10, 11, 12, 13, … 을 실행한다.
 
→ Result: 245(1), 246(1), 247(1), 245(1), 246(1) [context-switch instruction] 10(2), 11(2), 12(2), 13(2) [context-switch instruction] 247(1), 245(1), 246(1), …
 

Multiple threads

  • Thread
    • 스레드는 프로세스의 실행 흐름을 표현하는 하나의 가상 데이터 타입.
    • stack, pc, register set, state를 독립적으로 가지고 있다.
      • 여기서 pc는 CPU가 갖고있는 독립적인 pc와는 다르다.
      • CPU의 pc는 multi programming을 위한 프로세서의 instruction address를 나타낸다.
  • Multiple processes vs multiple threads
    • 하나의 프로세스 내부에서 여러개의 스레드를 관리한다면, context switch overhead를 줄일 수 있다. 코드, 데이터를 공유할 수 있다.
      • 스레드가 가지고 있는 정보가 프로세스가 가지고 있는 정보보다 상대적으로 적기 때문에, switch를 할 때마다 정보를 저장 / 읽기 에 소요되는 리소스가 적다
    • 다중 스레드를 사용한다면 스레드간에 동기화 하는 부분을 고려해야 한다 ( 단점 ).
      • 여러개의 스레드는 하나의 프로세스가 할당받은 address space를 사용할 수 있기 때문이다.
 

Layout of a program image

  • A program image
    • 하나의 프로세스가 사용하는 메모리 공간도 여러가지의 section 으로 구분된다.
 

Sample layout of a program image

notion image
 
  • Activation record
    • 메모리의 block은 process stack의 맨 위에 할당이 되는데, 함수가 호출이 됐을 때 execution context를 갖고 있기 위함
    • 각각의 함수가 실행될 때 새로운 activation record가 생성된다.
    • return address, parameter, status information, automatic variables 등을 포함한다.
 

Library function calls

  • SYNOPSIS box
    • 요약본 ( 더 자세하게 알기 위해서는 man command를 사용하자 )
    • 함수를 사용하기 위해선 어떠한 header file을 import 해야하고, function의 prototype을 알려 줌
  • Error
    • 전통적인 UNIX 함수의 경우 -1을 리턴해준다. ( 혹은 NULL )
    • errno라는 변수에 어떠한 에러가 일어났는지 에러 코드를 적어준다.
    • 새로운 라이브러리 함수의 경우 errno를 따로 사용하지 않고, 그 대신에 에러 코드 자체를 return
 

Error handling functions

  • void perror(const char *s)
    • #include <stdio.h>
    • errno에 대해 해당하는 에러 메세지를 화면에 출력해준다.
  • char* strerror(int errnum)
    • #include <string.h>
    • 보고싶은 에러 코드에 대해 에러 메세지를 return
 

Good model of a function

  • 함수를 실행하다가 에러가 났을 경우 exit 하지 말고, error 값을 return 하라
  • 버퍼의 사이즈가 불필요하게 가정해서 사용하지 마라 ( 잘 설계 해라.. )
  • 상수값을 임의의 값으로 정해서 사용하지 말고, 시스템에서 defined된 상수값이 있을 경우 그것을 써라
  • 함수가 파라미터를 받아서 이용한다면, 그 파라미터를 웬만하면 수정하지 말아라.
  • 가능하다면 static 변수, 동적 메모리 할당은 피해라
  • malloc family에 대해서는 잘 분석하여 사용해라
 

Argument arrays

  • string array 이다.
  • 리눅스 터미널 상에서 argument를 파싱하여 토큰으로 쪼갠다.
 

Thread-safe strtok()

string tokenizer 함수이다.
💡
여러개의 스레드가 동시에 호출할 때 문제가 될 뿐더러, 하나의 스레드가 동시에 두가지 이상의 strtok() 작업을 할 때에도 문제를 일으킬 수 있다.
 
example)
  1. strtok(”a b c d”, “ “); ⇒ return a
  1. strtok(NULL, “ “) ⇒ return b
strtok 자체에서 정적 변수로서 char *str 를 가지고 있기 때문에, 계속 진행하고 싶으면 null을 넣어주면 된다.
return 할 것이 없다면 null을 return 한다.
 
정적 변수를 사용하고 있기 때문에 thread safe 하지 않다.
 
  • strtok()의 문제
    • 내부적으로 static variable을 가지고 있다.
 
chatper02/wordaveragebad.c
1번 실행 시 여러 줄이 static variable에 저장 된다.
그 이후에 한줄이 나오자마자 2번을 실행하여 static variable에 저장된다.
다시 1번을 실행했을 때 제대로 tokenizing이 되지 않는다.
notion image
 

strtok_r

char* strtok_r(char*s, const char* sep, char **lasts)
  • lasts는 전역변수로 쓰이는 부분을 유저가 포인터로서 제공한다.
 

Use of static variables

strtok의 예시를 봤으니, 이를 방지하기 위해 최대한 정적 변수는 사용하지 않도록 하자
 
  • static 변수가 사용된 파일 내부에서만 access 가능
 

Process environment

환경변수 정보는 env cmd 를 사용해 확인 가능하다.
 
  • extern 변수 char **environ ⇒ Array<“key=value”>
  • char* getenv(const char* name)
    • 키 값을 argument로 하여 그에 대한 값을 받을 수 있는 함수
 

Process termination

  • Normal
    • main함수에서 return 되는 경우
    • main함수에서 끝까지 간 경우 내부적으로 return이 됨
    • 프로그램 중간에 exit, _Exit, _exit 함수를 호출한 경우
  • exit()
  • 마무리 작업에 해당하는 int atexit(void (*func)(void))
    • 등록된 함수를 exit 시에 실행할 수 있다.
    •  
  • Abnormal
    • abort 함수
    • 종료를 야기하는 signal을 받았을 때
    • core dump가 되는 경우