반응형

C++17에서의 mutex, lock

1. 기본 std::mutex 사용

std::mutex는 임계 구역(critical section)을 보호하기 위한 가장 기본적인 뮤텍스입니다.

#include <iostream>
#include <mutex>
#include <thread>

std::mutex mtx;

void print_message(const std::string& msg) {
    mtx.lock();
    std::cout << msg << std::endl;
    mtx.unlock();
}

int main() {
    std::thread t1(print_message, "Hello from thread 1");
    std::thread t2(print_message, "Hello from thread 2");

    t1.join();
    t2.join();
    return 0;
}
 

주의: lock()과 unlock()은 반드시 쌍으로 호출되어야 하며, 예외 발생 시 unlock이 호출되지 않아 데드락의 원인이 될 수 있음.


2. std::lock_guard 사용

std::lock_guard는 예외 안전성을 위해 사용되는 RAII 스타일의 뮤텍스 관리 도구입니다.

void print_message(const std::string& msg) {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << msg << std::endl;
}

스코프를 벗어나면 자동으로 unlock()이 호출됨.


3. std::unique_lock 사용

std::unique_lock은 lock_guard보다 더 유연한 뮤텍스 관리가 가능합니다. 예: 지연 잠금, 조건 변수와의 조합 등

void print_message(const std::string& msg) {
    std::unique_lock<std::mutex> lock(mtx);
    std::cout << msg << std::endl;
    // lock.unlock(); // 수동 해제도 가능
}

4. std::recursive_mutex

같은 쓰레드에서 여러 번 lock이 필요한 경우 사용합니다.

std::recursive_mutex rmtx;

void recursive_function(int count) {
    if (count <= 0) return;
    rmtx.lock();
    std::cout << "Depth: " << count << std::endl;
    recursive_function(count - 1);
    rmtx.unlock();
}

5. std::timed_mutex, std::recursive_timed_mutex

특정 시간 내에 lock을 얻지 못하면 포기하도록 설계된 뮤텍스입니다.

std::timed_mutex tmtx;

void try_lock_example() {
    if (tmtx.try_lock_for(std::chrono::milliseconds(100))) {
        std::cout << "Lock acquired" << std::endl;
        tmtx.unlock();
    } else {
        std::cout << "Timeout: failed to acquire lock" << std::endl;
    }
}

6. std::lock 함수

여러 뮤텍스를 동시에 안전하게 lock할 때 사용합니다. 데드락 방지를 위한 도구입니다.

데드락 케이스

// 쓰레드 A
m1.lock();
m2.lock(); // 잠금 대기 중

// 쓰레드 B
m2.lock();
m1.lock(); // 잠금 대기 중 → 데드락 발생!

쓰레드는 제 각각 돌기 때문에, 쓰레드A, B가 m1, m2를 lock을 한 다음 lock을 하게 되는 경우가 발생하게 되면 서로가 가진 뮤텍스를 기다리다가 영원히 대기 상태에 빠지게 됩니다.

#include <iostream>
#include <mutex>
#include <thread>

std::mutex m1, m2;

void threadA() {
    std::lock(m1, m2); // 안전하게 두 뮤텍스를 모두 잠금
    std::lock_guard<std::mutex> lk1(m1, std::adopt_lock);
    std::lock_guard<std::mutex> lk2(m2, std::adopt_lock);
    std::cout << "Thread A acquired both locks\n";
}

void threadB() {
    std::lock(m2, m1); // 순서를 바꿔도 안전하게 잠금
    std::lock_guard<std::mutex> lk1(m2, std::adopt_lock);
    std::lock_guard<std::mutex> lk2(m1, std::adopt_lock);
    std::cout << "Thread B acquired both locks\n";
}

int main() {
    std::thread t1(threadA);
    std::thread t2(threadB);

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

여기서 std::lock은 내부적으로 양쪽 쓰레드에서 같은 방식으로 동기화를 해주기 때문에 데드락 없이 둘 다 잠금에 성공할 수 있어요.


7. 주의사항 요약

  • 뮤텍스는 가능한 한 짧은 영역에서만 잠그고 풀어야 함
  • lock을 해제하지 않고 예외가 발생하면 데드락이 발생할 수 있음 → RAII 스타일 사용 권장
  • 여러 뮤텍스를 동시에 잠글 경우 반드시 std::lock 사용
  • 가능한 경우 std::scoped_lock (C++17부터 도입)을 사용하면 더 안전하게 여러 뮤텍스를 다룰 수 있음
std::mutex m1, m2;

void example() {
    std::scoped_lock lock(m1, m2);  // C++17: 데드락 방지 + RAII
    // 임계 구역
}
 

 

'Develop > C&CPP' 카테고리의 다른 글

[cpp] thread  (0) 2025.04.20
[cpp] atomic  (0) 2025.04.20
[cpp] cpp17에서 달라진 점  (0) 2025.04.20
[cpp] cpp14에서 추가된 것  (0) 2025.04.20
[service] 윈도우 서비스 프로그램  (0) 2025.01.05
반응형

C++17에서 달라진 점 (C++14와 비교)

C++17은 C++14에 비해 여러 가지 새로운 기능과 개선점을 도입하여, 개발자 생산성, 코드 가독성, 그리고 언어의 표현력을 크게 향상시켰습니다. 아래 표와 목록에서 주요 변경 사항을 정리합니다.

주요 변경점 비교

C++17
기능 c++14 c++17
Inline 변수 미지원 지원 (헤더 파일에서 변수 정의/초기화 가능)
구조적 바인딩 (Structured Bindings) 미지원 지원 (튜플, 구조체 분해 가능)
constexpr if 미지원 지원 (컴파일 타임 조건 분기)
Fold Expressions 미지원 지원 (가변 인자 템플릿 연산 간결화)
파일 시스템 라이브러리 미지원 지원 (std::filesystem)
병렬/동시 STL 알고리즘 미지원 지원 (병렬 실행 정책)
if/switch 초기화자 미지원 지원 (if/switch문에서 변수 선언 및 초기화)
중첩 네임스페이스 미지원 지원 (namespace a::b::c와 같이 간결하게 표현)
옵셔널 타입 미지원 지원 (std::optional)
클래스 템플릿 인자 추론(CTAD) 미지원 지원 (템플릿 인자 자동 추론)
인라인 변수 미지원 지원 (ODR 위반 없이 헤더에 변수 정의 가능)
 

C++17에서 추가된 주요 기능 및 개선 사항

  • Inline 변수: 헤더 파일에서 변수 정의/초기화 가능, ODR(One Definition Rule) 위반 방지
  • 구조적 바인딩 (Structured Bindings): 튜플, 구조체 등 복합 객체를 개별 변수로 분해할 수 있음
  •  
    cpp
    auto [x, y] = std::make_pair(1, 2);
  • constexpr if: 템플릿 코드에서 컴파일 타임 조건 분기 가능
  •  
    cpp
    if constexpr (조건) { /* ... */ }
  • Fold Expressions: 가변 인자 템플릿을 간결하게 연산할 수 있는 문법 도입
  •  
    cpp
    template<typename... Args> auto sum(Args... args) { return (args + ...); }
  • 파일 시스템 라이브러리(std::filesystem): 파일 및 디렉토리 작업을 표준화된 방식으로 지원
  • 병렬/동시 STL 알고리즘: 표준 라이브러리 알고리즘에 병렬 실행 정책 지원
  • if/switch 초기화자: if, switch문에서 변수 선언 및 초기화 가능
  •  
    cpp
    if (int x = func(); x > 0) { /* ... */ }
  • 중첩 네임스페이스: 여러 네임스페이스를 한 줄로 선언 가능
  •  
    cpp
    namespace a::b::c { /* ... */ }
  • std::optional: 값이 있을 수도 없을 수도 있는 상황을 명확하게 표현
  • 클래스 템플릿 인자 추론(CTAD): 객체 생성 시 템플릿 인자를 명시하지 않아도 자동 추론
  •  
    cpp
    std::pair p(1, 2); // std::pair<int, int>로 추론
  • 기타: std::variant, std::any, std::string_view 등 유틸리티 타입 추가, lambdas 개선, 기타 표준 라이브러리 확장

요약

  • C++14는 C++11의 기능을 다듬고 소폭 확장한 "마이너 업그레이드"였다면,
    C++17은 새로운 문법, 표준 라이브러리 확장, 컴파일 타임 프로그래밍 강화 등
    실질적인 "메이저 업그레이드"에 가까운 변화가 많습니다
  • 대부분의 기능은 기존 코드와의 호환성을 유지하면서,
    새로운 코드 작성 시 코드의 간결성, 안전성, 효율성을 크게 높여줍니다.

C++17로의 전환은 최신 컴파일러(GCC, Clang, MSVC 등)에서 모두 지원되며,
현대적인 C++ 코드를 작성하고자 한다면 적극적으로 권장됩니다

'Develop > C&CPP' 카테고리의 다른 글

[cpp] atomic  (0) 2025.04.20
[cpp] mutex, lock  (0) 2025.04.20
[cpp] cpp14에서 추가된 것  (0) 2025.04.20
[service] 윈도우 서비스 프로그램  (0) 2025.01.05
[server] ThreadPool, client 접속이 많을 때. TCP Server  (0) 2025.01.05

+ Recent posts