09.11 - TIL

김혁·2025년 9월 11일

TIL

목록 보기
16/84

오늘의 코드카타

카운트 다운

오늘의 공부

팀 프로젝트 진행 내용

  1. 모든 AI가 상태 변화가 동시에 일어나는 에러 수정
    • AICharacter 클래스에 FRandomStream 추가 및 BeginPlay 시 고유 ID 기반 시드 초기화.
    • Wait Random 태스크에서 FRandomStream을 사용하여 정해진 시간 내에서 랜덤 값을 블랙보드로 저장
    • 블랙보드로 저장된 값을 통해 Wait Blackboard Time 태스크를 활용해서 Idle 상태 구현
  2. 수정된 에셋에 맞게 메시 및 애니메이션 적용
  3. 서버에서 AI별 난수 생성 및 비헤이비어 트리 실행되게끔 구현

오늘의 CS

friend 키워드

  • 정의

    • 클래스의 캡슐화를 부분적으로 해제해서, 특정 함수나 다른 클래스가 private / protected 멤버에 접근할 수 있도록 하는 키워드
  • 특징

    1. 클래스 외부에서는 접근할 수 없는 멤버(private,protected)에도 접근 가능
    2. 접근 권한만 열어줄 뿐, 상속과는 관계가 없음
    3. A가 B를 friend로 선언해도, B가 A를 자동으로 friend로 가지는 건 아님(단방향)
    4. 컴파일 타임에 접근 권한이 결정됨
  • 사용법

    1. friend 전역 함수 : 전역 함수를 클래스 내부에 선언
    class Box {
    private:
        int width;
    public:
        Box(int w) : width(w) {}
    
        // friend 함수 선언
        friend void PrintWidth(const Box& b);
    };
    
    void PrintWidth(const Box& b) {
        cout << "Width: " << b.width << endl;
    }

    1. friend 클래스 : 다른 클래스를 friend로 지정하면 private 멤버 접근 가능
    class A {
    public:
    	friend class B;
    };
     
    class B {
    private:
    	int y;
    };

    1. friend 멤버 함수 : 특정 멤버 함수만 friend로 선언 가능
    class A;
    
    class B {
    public:
        void AccessA(A& a);
    };
    
    class A {
    private:
        int secret = 42;
        friend void B::AccessA(A& a);  // B의 특정 함수만 허용
    };
    
    void B::AccessA(A& a) {
        cout << "Accessing secret: " << a.secret << endl;
    }

    -> B의 멤버 함수인 AccessA에서 A의 private 멤버 변수인 secret에 접근 가능

멀티쓰레드에서 안전하게 쓸 수 있는 자료구조

1. 락 기반 (Lock-based) 자료구조

  • 가장 기본적인 접근 방법
  • std::mutex, std::lock_guard 등을 사용해 임계 구역 보호
  • 구현이 쉽지만, 병목이 생김
  • 사용 방법
    • std::vector, std::map, std::queue 등을 직접 뮤텍스에 감싸서 사용
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>

std::vector<int> data;
std::mutex mtx;

void worker(int id) {
    std::lock_guard<std::mutex> lock(mtx); // 임계 구역 보호
    data.push_back(id);
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);

    t1.join();
    t2.join();

    for (int v : data) 
    	std::cout << v << " ";		// 1 2
}

2. 락 프리 (Lock-free) 자료구조

  • 뮤텍스를 사용하지 않고 원자적(atomic) 연산으로 동시성 보장
  • std::atomic을 기반으로 동작
  • lock() 없이도 여러 쓰레드가 동시에 push/pop 가능 -> 효율적
  • Lock-free stack 예시
#include <atomic>
#include <memory>

template <typename T>
class LockFreeStack {
    struct Node {
        T data;
        Node* next;
        Node(T const& d) : data(d), next(nullptr) {}
    };
    std::atomic<Node*> head{nullptr};

public:
    void push(T const& value) {
        Node* newNode = new Node(value);
        newNode->next = head.load(std::memory_order_relaxed);
        while (!head.compare_exchange_weak(newNode->next, newNode));
    }

    std::shared_ptr<T> pop() {
        Node* oldHead = head.load();
        while (oldHead && !head.compare_exchange_weak(oldHead, oldHead->next));
        return oldHead ? std::make_shared<T>(oldHead->data) : nullptr;
    }
};

3. Thread-safe 컨테이너 (라이브러리)

  • C++ STL 컨테이너는 Thread-safe하지 않음
    -> 외부 라이브러리를 통해 제공되는 자료구조가 있음
  • Intel의 TBB(Threading Building Blocks)의 concurrent 컨티이너 활용

TBB (Threading Building Blocks)

  • C++에서 병렬 프로그래밍을 위한 라이브러리
  • 멀티쓰레드 환경에서 안전하게 사용할 수 있는 컨테이너를 제공함
  • 기본적으로 동기화 메커니즘을 통해 동시 접근을 관리하기 때문에, 단일 쓰레드 환경에서는 일반 컨테이너를 사용하는 것이 더 효율적

1. concurrent_vector

  • 특징
    • std::vector와 비슷한 동적 배열
    • 여러 쓰레드에서 동시에 안전하게 읽기 연산 가능
    • 원소를 추가하는 연산은 여러 쓰레드에서 동시에 수행 가능
  • 제약
    • 원소를 제거하거나 벡터의 크기를 줄이는 연산은 동시에 수행 불가능
    • 따라서 append-only 시나리오에 적합
  • 설명 홈페이지 : MS - concurrent_vector

2. concurrent_queue

  • 특징
    • FIFO(선입선출) 큐
    • 여러 쓰레드에서 동시에 push() / try_pop() 가능
    • Lock-Free로 구현 -> 높은 성능
  • 제약
    • 용량 제한 없음

3. concurrent_unordered_map / concurrent_unordered_set

  • 특징
    • 해시 기반 연관 컨테이너
    • 여러 쓰레드에서 동시에 insert()/erase()/find() 안전
    • 내부적으로 분할된 버킷에 락을 걸어 병렬성 극대화
  • 제약
    • 순회 시점에 따라 요소가 추가/삭제될 수 있음

4. concurrent_priorty_queue

  • 특징
    • 우선순위 큐 (default : max-heap)
    • 여러 쓰레드에서 동시에 push() 가능
    • try_pop()은 가장 높은 우선순위 원소를 반환
  • 제약
    • erase() 같은 임의 원소 제거 불가

-> TBB의 concurrent 컨테이너들은 삽입/탐색/읽기 위주의 병렬 연산에 강점

profile
게임 개발자를 향해..

0개의 댓글