일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- Go디자인패턴
- Golang디자인패턴
- line챠트
- go리플렉션성능
- 챠트그리기
- 디자인패컨
- GO벤치마킹
- Iperf3
- snoflake
- vue3 통신
- GObenchmark
- Go성능테스트
- Golang벤치마킹
- vue3
- vue3 axios
- Golang부하테스트
- 리플렉션성능
- 디자인패턴학습필요성
- GO부하테스트
- Vue.js
- pprof
- Go벤치마크
- go로드맵
- Line차트
- vue3-chartjs
- golang벤치마크
- golang uuid
- Golang성능테스트
- Golangbenchmark
- 대역폭측정하기
- Today
- Total
import ( "코딩", "행복", "즐거움" )
Thread와 atomic 본문
c++개발 안한지 10년 가까이 되어 가는 것 같다.
현재는 현업에서 golang과 C#으로 개발 중이다.
필요한 일이 생길 수도 있어
c++ 감을 찾기위해 간단 히 포스팅 해본다.
Thread
_beginthreadex 를 쓰던 시절이 기억난다.
c++ 11에 추가된 thread 녀석은 매우 간결하다. (설명이 필요없음)
간단한 함수 만들고..
void Test()
{
for (int i = 0; i < 10000; i++)
{
std::cout << i << std::endl;
}
}
스레드로 실행 , join()은 thread 함수가 끝날 때 까지 대기한다.
auto th = std::thread(Test);
th.join();
atomic
네트워크 프로그래밍을 하려면 thread에 대한 이해가 필수적이다.
thread가 여러개일 경우 공유 데이터에 접근해야 하는 경우
"동기화"가 필수 적이다.
이런 "동기화" 처리는 매우 위험한 상황을 초래할 수 있기 때문에
현업에서는 효율성을 희생하고, 안정성을 택하여
큐를 이용해 스레드간 동기화를 하는 경우가 많다.
하지만 극한의 성능을 뽑아햐는 경우는 생기는 법
이럴 경우에는 결국 멀티스레드 프로그래밍을 해야 한다.
atomic은 동기화 기술중 하나로
공유자원에 동시접근을 해야 하는 변수가 있을 때 원자적인 연산을 가능하게 해준다.
예를 들어 다음의 코드를 보자
int a = 0;
a += 1;
간단 한 코드이지만, 디어셈블리에서 처리 순서를 보면
1) 데이터의 값을 레지스터에 복사
2) 레지스터에서 값 증가
3) 레지스터에서 연산한 결과값을 해당 주소로 복사
위 처리가 멀티스레드에서 동작한다면 어떻게 될까 ?
코드에서는 한줄이지만, 실제 동작은 3가지로 구분되기 때문에
3가지 동작이 완료되기 전 아무 시점에나 다른 스레드의 개입이 발생 할 수 있다.
이럴 경우 원자적으로 단 한번만 처리하게 해주려면
atomic과 같은 클래스를 사용 하면 된다.
atomic으로 변수선언과 증가 처리 예제 ..
std::atomic<int> sum = 0;
void Test()
{
for (int i = 0; i < 10000; i++)
{
sum.fetch_add(1);
std::cout << sum << std::endl;
}
}
디어셈블리로 확인해보면 fetch_add로 한줄로 처리 되는 걸 확인 할 수 있다.
굳이 fetch_add() 함수를 사용하지 않고 ++ 연산을 하더라도
동일하게 처리되는 것을 확인 할 수 있다.
함수를 쓰게 되면 장점은 명시적으로 이 변수는 스레드 동기화 되고 있구나라고
개발자가 인지할 수 있게 되어 좋다.
'C++' 카테고리의 다른 글
CAS ( Compare and swap ) (0) | 2022.10.07 |
---|---|
RAII (Resource Acquisition Is Initialization) (0) | 2022.10.04 |