일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 영속성
- directx
- 병행성 관련 오류
- I/O장치
- 멀티쓰레드
- 그리디 알고리즘
- codility
- 프로그래머스
- 알고리즘
- 파일시스템 구현
- 락
- 동적계획법
- 운영체제
- DirectX12
- 그리디알고리즘
- Direct12
- 멀티프로세서
- 다이나믹프로그래밍
- 렌더링 파이프라인
- 병행성
- 백준
- 자료구조
- DirectX 12
- 타입 객체
- 컨디션 변수
- OS
- 쓰레드
- 다이나믹 프로그래밍
- 스케줄링
- 디자인패턴
- Today
- Total
목록멀티쓰레드 (8)
기록공간

수년 동안 병행성 관련 오류 해결을 위해 연구자들이 엄청난 시간과 노력을 들였다. 대부분의 초기 연구는 교착 상태(deadlock)에 초점이 맞추어져 있었다. 최근 연구들은 다른 종류의 병행성 버그들을 다루고 있다. 실제 프로그램에서 발견된 사례를 중심으로 어떤 오류가 있는지를 살펴보고자 한다. 오류의 종류 첫 번째 질문은 이것이다 : 복잡한 병행 프로그램에서 발생하는 병행성 오류들은 어떤 것들이 있는가? 이 질문에 대한 답을 구하는 것은 어렵지만, 다행히 다른 사람들이 이미 비슷한 작업을 해놓았다. 실제 상황에서 어떤 종류의 오류들이 발생하는지 이해하기 위해 그들은 많이 사용되는 병행 프로그램들을 자세히 분석하였다. 이 연구는 대표적인 오픈소스 프로그램 4개에 집중하였다. 유명한 DBMS(데이터 베이스..

세마포어는 정수 값을 갖는 객체로서 두 개의 루틴으로 조작할 수 있다. 이 두 개의 루틴은 각각 sem_wait()와 sem_post()이다. 세마포어는 초기값에 의해 동작이 결정되기 때문에, 사용하기 전 "제일 먼저" 값을 초기화해야 한다. class semaphore { int value; semaphore() {value = 1;} }; 세마포어 객체 정수 값을 1로 초기화 한다. 이제 세마포어 내에 있는 sem_wait()와 sem_post() 메서드를 살펴보도록 하겠다. 이 둘은 원자적으로 실행된다. 레이스 컨디션 (쓰레드 간의 공유하는 값을 서로 쓰려고 하는 경쟁상태)이 발생할 수 있다는 사실은 걱정하지 말자. 그것은 곧 락과 컨디션 변수를 사용하게 될 것이다. * sem_wait() int ..
지금까지 락의 개념을 학습하고 하드웨어와 운영체제의 적절한 지원을 통해 제대로 된 락을 만드는 법을 살펴보았다. 불행히도 "락"만으로는 병렬 프로그램을 제대로 작성할 수 없다. 쓰레드가 계속 진행하기 전에 어떤 조건(Condition)이 참인지를 검사해야 하는 경우가 많이 있다. 예를 들어 부모 쓰레드가 작업을 시작하기 전에 자식 쓰레드가 작업을 끝냈는지를 검사하기를 원할 수 있다.(보통 join() 연산이라고 불린다) 이러한 대기문은 어떻게 구현해야 할까? void child() { std::cout

흔하게 사용되는 자료 구조에서 락을 사용하는 방법을 살펴보도록 하겠다. 자료 구조에 락을 추가하여 쓰레드가 사용할 수 있도록 만들면 그 구조는 쓰레드 사용에 안전(thread safe)하다고 할 수 있다. 물론 락인 어떤 방식으로 추가되었느냐에 따라 자료 구조의 정확성과 성능을 좌우할 것이다. 병렬 카운터 카운터는 가장 간단한 자료 구조 중 하나이다. 보편적으로 사용되는 구조이면서 인터페이스가 간단하다. 간단하지만 확장성이 없음 동기화되지 않은 카운터는 몇 줄 안되는 코드로 작성할 수 있는 평범한 자료 구조이다. 다음은 락이 없는 카운터의 코드이다. class counter_t { int value; public: counter_t() {value = 0:} void increment() {value++..

Fetch-And-Add 마지막 하드웨어 기반의 기법은 Fetch-And-Add 명령어로 원자적으로 특정 주소의 예전 값을 반환하면서 값을 증가시킨다. C, C++ 코드로 표현하면 다음과 같다. // C int FetchAndAdd(int *ptr) { int old = *ptr; *ptr = old + 1; return old; } // C++ #include int FetchAndAdd(std::atomic_int &ptr) { return ptr++; } C++ 코드를 보면 atomic_int이 보일 것이다. 이건 무엇일까? C++11부터 지원하는 Atomic 자료구조이다. 이것은 기본 자료 구조의 일부를 원자적으로 구현해놓은 것이다.(char, int, short, bool) Atomic 자료구조..

위에서 살펴봤듯 멀티 프로세서에서는 인터럽트를 중지시키는 것이 의미가 없기 때문에 시스템 설계자들은 락 지원을 위한 하드웨어 설계를 하기 시작했다. 오늘날 모든 시스템들은 하드웨어 지원 기능을 가지고 있으며, 단일 CPU 시스템 또한 이런 기능이 존재한다. Test-And-Set (Atomic Exchange) 하드웨어 기법 중 가장 기본은 Test-And-Set 명령어 또는 원자적 교체(atomic exchange) 라고 불리는 기법이다. Test-And-Set 명령어를 사용하면 락을 간단하게 구현할 수 있다. ptr이 가리키는 이전 값을 old로 받아 리턴(TEST)한다. 동시에 그 값을 new로 바꾼다(SET). 이 동작은 원자적으로 수행되어야 하며 중간에 인터럽트 될 수 없다. 때문에, 소프트웨어..

여러 개의 명령어들을 원자적(atomic)으로 실행해보고 싶지만 병행성으로 인한 여러 쓰레드의 개입으로 인해(임계영역) 그렇게 할 수가 없었다. 여기서는 앞서 다룬 락(lock)을 이용하여 이 문제를 직접적으로 다루고자 한다. 프로그래머들은 소스 코드의 임계 영역을 락으로 둘러 그 임계 영역이 하나의 원자 단위 명령어인 것처럼 실행되도록 한다. 락 : 기본 개념 예를 위해 다음의 임계 영역이 있다고 하자. 공유 변수의 갱신이다. balance = balance + 1; 그리고 락으로 임계 영역을 다음과 같이 감쌌다. mutex mylock; // 전역 변수로 선언된 mylock ... mylock.lock(); balance = balance + 1; mylock.unlock(); 락은 하나의 변수이므로..

이번 장에서는 프로세스를 위한 새로운 개념인 쓰레드(thread)를 소개한다. 프로그램에서 한 순간에 하나의 명령만을 실행하는 고전적인 관점에서 벗어나 멀티 쓰레드 프로그램은 하나 이상의 실행 지점(독립적으로 실행 가능한 Program Counter값)을 가지고 있다. 멀티 쓰레드와 프로세스의 차이가 있다면 주소 공간을 공유하기 때문에 동일한 값에 접근할 수 있다. 하나의 쓰레드 상태는 프로세스의 상태와 매우 유사하다. 쓰레드는 프로그램 카운터(PC)와 연산을 위한 레지스터들을 가지고 있다. 만약 두 개의 쓰레드(T1, T2)가 하나의 프로세서에서 실행 중이라면 실행하고자 하는 쓰레드(T1)는 반드시 문맥 교환(context switch)을 통해서 실행 중인 쓰레드(T2)와 교체되어야 한다. 문맥 교환은..