전체 글

전체 글

    [Async] shared_future

    [Async] shared_future

    shared_future future와 promise는 1:1 매칭이 되어야하기 때문에 복사가 불가능하다. 하지만 promise를 통해 하나의 value가 set이 되면 이를 여러 곳에서 읽어야 하는 경우가 있을 수 있다. 여러 future에서 value를 읽어야하는 경우 Copy가 가능한 것이 shared_future이다. Example Code : shared_future 사용 #include #include #include #include #include void fn(std::shared_future fut) { std::cout

    [Async] Future, Promise

    [Async] Future, Promise

    Future, Promise future와 promise는 커뮤니케이션 채널을 만드는 하나의 쌍이다. 이 채널을 통해 전달할 수 있는 신호는 Data, Exception, Signal 그리고 각 promise와 future는 다른 thread에 있어도 되고 같은 thread에서 커뮤니케이션을 해도 된다. 간단하게 코드부터 확인해보자. Single Thread 예제 Example Code #include #include #include int main() { // 데이터를 넣을 수 있는 promise 생성 std::promise prms; // promise와 한 쌍이될 수 있는 future를 get_future함수를 통해 생성 std::future fut = prms.get_future(); // set..

    [Async] 비동기 함수 Introduction

    [Async] 비동기 함수 Introduction

    비동기 함수, std::async 이전에 thread, mutex, condition_variable과 같은 저수준의 Concurrency 프로그래밍을 배웠다. 하지만 이를 많이 사용하면 코드가 복잡해지고 가독성이 떨어지는 것도 사실이다. 그래서 C++에서는 더 high level의 concurrency 기능을 제공하고 있지만 좋지 못한 성능 때문에 덜 사용되고 있다. 그래도 성능보다 가독성, 생산성이 필요한 곳에서는 사용할 수 있기 때문에 알아두는 것이 좋다. 비동기 함수란 간단하게 설명하자면 어떤 Task가 Main thread에서 처리가 되길 기다리는 것이 아니라 비동기적으로 다른 곳에서 실행하고 Main thread는 Task의 완료된 결과값이 필요할 때만 가져다 사용하는 것이다. Main thr..

    [Thread] std::latch

    [Thread] std::latch

    std::latch (C++20) latch는 문고리라는 뜻인데 일정 조건을 만족하면 문고리가 열리면서 wait 상태였던 쓰레드들이 자신들의 일을 계속 수행할 수 있다. latch는 카운터 베이스이기 때문에 세마포어와 비슷하다고 생각할 수 있지만 세마포어와 다르게 latch는 카운터가 감소하기만하는 특징을 가지고 있다. cppreference를 보면 latch는 카운트를 reset하거나 증가시키는 방법은 없다고 정의되어있다. latch의 초기 카운트가 2라고 가정하였을 경우 쓰레드들이 일을 수행하는데 처음 latch의 count_down() 함수를 통해 카운트가 1로 감소하고 wait()함수를 통해 해당 쓰레드는 block이 된다. 이 후 다른 쓰레드가 진행되면서 count_down()을 하면 latch..

    [Thread]semaphore

    [Thread]semaphore

    semaphore (C++20) mutex와 비슷하면서도 다르다. 리소스 제한을 위해 사용하거나 signal을 보낼 때도 사용할 수 있다. 기본 개념을 보면 세마포어는 내부에 카운터를 가지고 있다. 그림으로 잠시 확인해보면, 가운데 숫자 2는 초기 카운트이며 아무리 많은 쓰레드가 리소스를 획득하려해도 동시에 2개의 쓰레드만 해당 리소스로 접근이 가능하다. acquire는 카운터가 1개 줄어들고 release는 카운터가 1개 증가한다. 만약, 카운트가 0인 상태에서 acquire 시도하면 해당 쓰레드는 wait 즉,block 상태가 된다. 나중에 다른 쓰레드가 release를 통해 카운터를 하나 증가시킨다면 wait상태에 있던 쓰레드가 이를 가져가서 다시 카운터를 0으로 만들고 계속해서 일을 수행한다. C..

    [Thread] Producer-Consumer 패턴

    [Thread] Producer-Consumer 패턴

    Producer-Consumer(생산자-소비자) 패턴 추상적인 패턴이기 때문에 만드는 방법이 다양하며 multi threaded 프로그래밍에서 상당히 많이 쓰이는 패턴이다. 예를 들어, Job queue를 생각해 볼 수 있다. 왼쪽은 Job을 만들어서 추가하는 Producer가 되고 오른쪽이 Job을 가져와 처리하는 Consumer쪽이 된다. Job Queue에 1초에 2개의 Job이 들어오고 처리하는 쪽에서는 1초에 오직 하나의 Job만 처리할 수있다고 한다면 처리하는 쪽에 2개 이상의 Thread를 생성하여 Job Queue가 오버플로우되지 않도록 처리하는 구조를 가져갈 수 있을 것이다. 예를 들어, 왼쪽 Producer쪽에서 Job을 추가하려면 Job Queue(shared memory)에 오직 하..

    [Thread] Condition Variable

    [Thread] Condition Variable

    Condition Variable Concurrency 프로그래밍을 한다면 필수적으로 알아야하는 개념이다. Condition Variable을 사용하는 목적은 하나의 Thread에서 다른 Thread로 신호를 보낼 때 사용한다. 자세히 알아보기 위해 그림을 보면, 실행 과정 Wait Thread는 진행 과정 중에 condition variable의 wait() 함수를 만나면서 block 상태가 된다. 다른 Thread에서 두 Thread간의 공유되는 변수 condition(var)의 값을 수정하고 condition variable을 통해서 signal을 보낸다. block 상태에 있던 Wait Thread는 신호를 받고 var를 체크한 뒤 조건이 만족되면 해당 Thread를 계속 진행한다. 여기서 신호(..

    [Thread] scoped static 초기화

    [Thread] scoped static 초기화

    scoped static initialization c++ concurrency 프로그래밍을 하기 위해서는 꼭 알아야 하는 개념이다. 먼저 scoped static이 무엇인지 코드를 통해 알아본다. Example Code : scoped static 다음 예제는 단순히 static 변수를 선언하고 있는 함수 fn()을 호출하는 예제이다. void fn() { static int i = 0; } int main() { fn(); // fn(); // fn(); // fn(); return 0; } 메모리 접근 위에서 변수 i 는 stack도 아니고 heap도 아닌 static이라는 공간에 저장된다. 이는 static이라는 공간에 저장했기 때문에 프로세스 안에서 오직 하나만 존재한다. 함수 fn을 아무리 반..