Threads_Concurrency

Oak_Cassia·2022년 1월 30일
0

Threads & Concurrency

스레드

  • CPU 이용의 기본 단위.
  • 스레드 ID, 프로그램 카운터. 레지스터 집합. 스택으로 구성된다.
  • 같은 프로세스의 스레드와 코드, 데이터 섹션, 열린 파일이나 신호 같은 운영체제 자원들을 공유
  • 같은 작업을 하는데 새 프로세스를 만드는 것보다 새 스레드를 만드는게 효율적이다.
  1. 클라이언트 -(요청)> 서버
  2. 서버-요청을 서비스할 새로운 스레드 생성한다.
  3. 서버-추가적인 클라이언트 요청을 listen 하는 작업을 재개한다.

스레드의 장점

responsiveness(응답성)
응용프로그램의 일부분이 봉쇄되거나 긴 작업을 수행해도 프로그램의 수행이 계속 되는 것 허용
resource sharing
스레드는 자동으로 프로세스의 자원들과 메모리를 공유한다.
economy
자원을 공유하기 때무넹 스레드를 생성하고 문맥 교환하는 것이 경제적이다.
scalability(규모 적응성)
다중 스레드의 이점은 다중 처리기 구조에서 더욱 증가할 수 있다.

다중 코어 프로그래밍

  • 각 코어는 운영체제에 별도의 CPU로 보인다.
  • 다중코어 시스템을 위해 프로그래밍 하기 위해서는 5개의 극복해야할 도전과제가 있다.
  1. identifying tasks: 응용을 분석하여 독립된 병행 가능 태스크로 나눌 수 있는 영역을 찾는 작업이 필요하다. 이상적으로 태스크는 서로 독립적이고 따라서 개별 코어에서 병렬실행될수 있어야 한다.
  2. balance: 전체 작업에 균등한 강도를 갖게 태스크로 나누는 것도 중요하다. 기여도가 적은 작업은 별도의 코어를 사용하면 손해(?)다
  3. data spliting: 태스크가 접근하고 조작하는 데이터 또한 개별코어에서 사용할 수 있도록 나눠져야 한다.
  4. data dependency: 태스크가 접근하는 데이터는 둘 이상의 태스크 사이에 종속성이 없는지 검토되어야 한다. 피치 못한 경우 프로그래머가 데이터 종속성을 수용할 수 있도록 태스크의 수행을 잘 동기화 해야한다.
  5. testing and debugging: 병렬로 실행될 때 다양한 실행 경로가 존재할 수 있다. 시험하고 디버깅하기 더 어렵다
  • 데이터 병렬 실행: 데이터의 부분집합을 다수의 계산 코어에 분배한 뒤 각 코어에서 동일한 연산을 실행
  • 태스크 병렬 실행: 태스크(스레드)를 다수의 코어에 분배한다. 각 스레드는 고유의 연산을 실행한다. 동일한 데이터에 연산을 하거ㅏ 다른 데이터에 연산을 할 수 있다.

사용자 스레드는 커널 위에서 지원된다. 커널의 지원 없이 관리된다.
커널 스레드는 운영체제에 의해 직접 지원되고 관리 된다.

  • Many to one Model: 많은 사용자 수준 스레드를 하나의 커널 스레드로 사상한다.
    한 스레드가 봉쇄형 콜을 하는 경우 전체, 한번에 하나의 스레드만 커널에 접근할 수 있다.
  • one to one Model: 각 사용자 스레드를 각각 하나의 커널 스레드로 사상한다. 병렬 수행 가능
  • many to many Model: 여러 개의 사용자 수준 스레드를 그보다 작거나 같은 수의 커널 스레드로 멀티플렉스 한다.
  • two level Model: 다대다 모델의 변형, 다대다+중요한 것들은 일대일로 사용

Threads Library
프로그래머에게 스레드를 생성하고 관리하기 위한 API를 제공한다.

구현방법

  1. 커널의 지원 없이 완전한 사용자 공간에서 라이브러리 제공. 라이브러리의 함수를 호출하는 것은 사용자 공간의 지역함수를 호출하게 된다는 것을 의미
  2. OS에 의해 지원되는 커널 수준 라이브러리를 구현 API를 호출하는 것은 시스템 콜을 부르는 결과를 낳는다.

비동기 스레딩: 부모가 자식 스레드를 생성한 후 부모는 자신의 실행을 재개. 부모와 자식 독립적으로 병형 실행 다중 스레드 서버, 반응형 사용자인터페이스설계등에 쓰임

동기 스레딩: 부모 스레드가 한 이상의 자식 스레드를 생성한뒤 그들이 종료할 때까지 대기 데이터 공유 양이 많다.
자식 스레드가 조인을 해야 부모스레드 실행 가능

Implicit Threading: 스레딩의 생성과 관리 책임을 응용 개발자로부터 컴파일러와 실행시간 라이브러리에게 넘겨주는 것. 개발자는 병렬작업만 식별하면 된다.

thread pool: 프로세스를 시작할 때 일정한 수의 스레드를 미리 풀로 만들어 두는 것
서버는 요청을 받으면 스레드 풀에 제출. 풀에 사용가능한 스레드가 있으면 깨어나고 없으면 생길 때 까지 작업이 대기된다. 스레드가 서비스를 완료하면 풀로 복귀
장점: 새스레드를 만드는 것보다 기존 스레드로 서비스 해주는 것이 종종 빠르다.
스레드 수의 제한을 둬 사양이 낮은 시스템에 도움이 된다.

Fork-Join: 부모스레드가 하나 이상의 자식 스레드를 생성한 다음 자식의 종료를 기다린 후 join하고 그 시점부터 자식의 결과를 확인하고 결합할 수 있다.
라이브러리가 생성할 실제 스레드 수를 결정하는 동기 버전의 스레드 풀

OpenMP: c/c++, Fortran으로 작성된 API와 컴파일러 디렉티브의 집합. 공유 메모리 환경에서 병렬 프로그래밍을 하게 도와준다.
병렬로 실행될 수 있는 블록을 찾아 병렬 영역이라 부른다.
병렬 영역에 컴파일러 디렉티브 삽입
이 디렉티브는 OpenMP 실행시간 라이브러리에 해당영역을 병렬로 실행하라고 지시
시스템의 코어 개수만큼 스레드 생성.
개발자가 병렬화 수준 선택 가능

Gran Central Dispatch: 애플꺼
Intel 스레드 빌딩 블록

Threading Issues

다중 스레드 프로그램을 설계할 때 고려해야할 몇가지 문제들
Fork()및 Exec() 시스템 콜: Fork() 후 exec()를 부르면 모든 스레드를 다 복제해서 만들어 주는 것은 불필요하다.
Fork()후 exec()를 하지 않는다면 새 프로세스는 모든 스레드들을 복제해야 한다.
signal handling: 프로세스에 어떤 이벤트가 일어났을 때 알리기 위해 사용
신호는 특정 이벤트가 일어나야 생성된다.
생성된 신호가 프로세스에 전달된다.
신호가 전달되면 반드시 처리되어야 한다.
동기식 신호: 불법 메모리 접근, 0으로 나누기, 신호발생 연산을 수행한 동일한 프로세스에 전달
비동기식 신호: 신호가 실행중인 프로세스 외부에서 발생하면 신호를 비동기식으로 전달 받는다.
디폴트 처리기: 모든 신호는 커널이 실행시키는 디폴트 신호 처리기가 있다.
사용자 정의 처리기: 디폴트 처리기를 대체할 수 있다.

thread cancellation: 스레드가 끝나기 전에강제 종료 시키는 작업
target thread: 최소 되어야할 스레드
비동기식 취소: 한 스레드가 즉시 목적 스레드를 강제 종료
지연 취소: target thread가 주기적으로 자신이 강제 종료 돼야할지 점검

스레드 로컬 저장장치: 상황에 따라 각 스레드가 자기만의 데이터를 가져야할 필요도 있다. 그러한 데이터를 thread-local storage, TLS라 부른다.
scheduler activations: 커널은 응용에 가상처리기LWP의 집합을 제공하고 응용은 사용자 스레드를 가용한 가상 처리기로 스케줄한다. 커널은 응용에게 특정 이벤트에 대해 알려 줘야한다.(upcall)

LWP: 경량 프로세스 사용자와 커널 스레드 사이의 중간 자료구조

profile
rust로 뭐할까

0개의 댓글