고급 자바 8 교육 (6일 중 3일차)
티맥스소프트 연구소에 연구소장으로 재직 중이던 2013년 10월에 진행한 자바 언어 강의 내용입니다.
JVM에 대한 이해와 Java 8에 대한 소개를 포함하려고 노력하였습니다.
아래 강의 동영상이 있습니다.
http://javadom.blogspot.com/2017/07/8-6.html
고급 자바 8 교육 (6일 중 2일차)
티맥스소프트 연구소에 연구소장으로 재직 중이던 2013년 10월에 진행한 자바 언어 강의 내용입니다.
JVM에 대한 이해와 Java 8에 대한 소개를 포함하려고 노력하였습니다.
아래 강의 동영상이 있습니다.
http://javadom.blogspot.com/2017/07/8-6.html
고급 자바 8 교육 (6일 중 3일차)
티맥스소프트 연구소에 연구소장으로 재직 중이던 2013년 10월에 진행한 자바 언어 강의 내용입니다.
JVM에 대한 이해와 Java 8에 대한 소개를 포함하려고 노력하였습니다.
아래 강의 동영상이 있습니다.
http://javadom.blogspot.com/2017/07/8-6.html
고급 자바 8 교육 (6일 중 2일차)
티맥스소프트 연구소에 연구소장으로 재직 중이던 2013년 10월에 진행한 자바 언어 강의 내용입니다.
JVM에 대한 이해와 Java 8에 대한 소개를 포함하려고 노력하였습니다.
아래 강의 동영상이 있습니다.
http://javadom.blogspot.com/2017/07/8-6.html
2. 하이젠버그
● 이 버그는 문제가 있음이 확실하지만 재현이 어려움
○ ex) 오류 탐색을 위한 코드로 인해 재현이 안되는 경우
● 용어의 유래
○ 불확정성의 원리: 베르너 하이젠 베르크
○ 하이젠버그 = 하이젠 + 버그
3. 멀티스레드 버그-데이터 레이스
● 데이터 레이스
○ 공유 데이터가 두 스레드 이상에서 동시에 접근
○ 단, 하나의 접근이 쓰기인 경우
int global_data = 0;
DWORD CALLBACK ThreadFunc(void* thread_id) {
for(int i = 0; i < 10000000; i++)
++global_data;
printf("result = %dn", global_data);
}
○ 2개의 스레드에 의해 위 함수가 실행될 때 그 결과를 예
측할 수 없음
4. 멀티스레드 버그 - 원자성 위반
● 일련의 작업이 침범 받지 않고 안전하게 수행되지 못함
○ 데이터 레이스가 아니지만 오류 발생
모질라 nxXULDocument.cpp에서 발견
Thread_1 Thread_2
void LoadScript(nsSpt * aspt) {
Lock(1);
gCurrentScript = aspt;
LaunchLoad(aspt);
Unlock(1);
} Lock(1);
gCurrentScript = NULL;
// LaunchLoad의 결과로 Unlock(1);
// 비동기적으로 Callback
void OnLoadComplete() {
Lock(1);
gCurrentScript->compile();
Unlock(1);
}
5. 멀티스레드 버그 - 순서 위반
● 의도한 순서가 멀티 스레드 상황에서 지켜지지 않을 경우
모질라의 순서 위반 버그
Thread_1 Thread_2
int ReadWriteProc(...) { void DoneWating(..) {
... ...
PBReadAsync(&P); io_pending = TRUE;
io_pending = TRUE; ...
}
...
while(io_pending) {
...
}
}
6. 해결 방안
● 데이터 레이스
○ 락으로 수정 가능
● 그외의 멀티 스레드 버그
○ 락의 순서 조정
○ 현재의 락만으로는 모든 병행성 문제를 해결할 수 없음
○ 알고리즘의 수정
■ 자료 구조 및 알고리즘을 병행성 문제가 없도록 수정
7. 결론
● 멀티 스레드 버그는 재현이 힘들어서 디버깅이 힘들다.
● 락으로 데이터 레이스 문제를 해결할 수 있지만, 멀티스레드
문제 전체를 해결 할 수는 없다.
9. 병렬 프로그래밍의 문제: 가짜 공유
● 공유되지 않는 데이터 인데 캐시 구조의 특성으로 공유되는
것으로 인식 => 성능 저하 현상 발생
volatile int data1;
volatile int data2;
DWORD CALLBACK TestThread1( ... ) {
// 0번 CPU에서 작동
SetThreadAffinityMask(GetCurrentThread(), 1 << 0);
for(int i = 0; i < 150000000; ++i)
data1 = data1 +1;
}
DWORD CALLBACK TestThread2( ... ) {
// 2번 CPU에서 작동
SetThreadAffinityMask(GetCurrentThread(), 1 << 0);
for(int i = 0; i < 150000000; ++i)
data2 = data2 +1;
}
10. 가짜공유문제 - Cont'd
● 0번 코어가 Data1을 1번 코어가 Data2를 사용
● 양쪽 코어의 같은 캐쉬 라인에 위치하게 됨
○ 캐시는 일반적으로 4바이트 이상이 한 단위로 처리
○ 두 변수의 주소가 인접
● 코어가 한 캐시라인을 업데이트 하면 다른 코어가 가진 사본
을 모두 무효화
○ 즉, 가짜 공유 문제 발생
○ 양쪽 모두 계속해서 캐시 미스 발생
코어 0 코어 1
data1 data2
1 2 1 2
11. 가짜 공유 문제 - Cont'd
● 해결책
○ 캐쉬 선언 만큼 데이터 선언을 분리
#define CACHE_LINE 64
#define CACHE_ALIGN_MSVC __declspec(align(CACHE_LINE))
#define CACHE_ALIGN_GCC __attribute__((aligned(CACHE_LINE)))
volatile CACHE_ALIGN_MSVC int data1;
volatile CACHE_ALIGN_MSVC int data2;
volatile struct {
int data1;
char padding[CACHE_LINE];
int data2;
} DATA;
12. 미래의 병렬 프로그래밍 방법론
● 병행성 해결을 위한 하드웨어적 방법
○ 트랜잭셔널 메모리(TM)
■ 원자적으로 실행될 부분을 키워드로 선언
void TransferValue(FIFO Q1, FIFO Q2) {
__atomic { // 트랜잭션 영역
v = Q1.dequeue();
Q2.enqueuue(v);
}
}
■ 충돌이 감지되면, 트랜잭션을 무효화 하고, 다시 실행
■ TM 블록 내에 I/O가 있을 경우 재실행이 힘듬
■ ACID중 원자성과 독립성만 보장
■ 10년 내에 실용화 가능성이 있음
13. 미래의 병렬 프로그래밍 방법론-
Cont'd
● 병행성 해결을 위한 하드웨어적 방법
○ 스레드 수준 투기(TLS)
■ 분기 예측과 메모리 실행을 스레드 수준까지 올림
■ 어떤 코드를 먼저 여러 스레드에서 실행 후, 충돌이
없다면 병렬로 실행
■ 컴파일러가 적절하게 TLS를 활용한 코드를 생성
■ 이론상으로만 존재
14. 결론
● 가짜 공유 문제는 멀티 코어 구조로 인한 것이므로 프로그래
머의 주의가 필요
● 앞으로의 병렬 프로그래밍 방법
○ 하드웨어적 방법
■ 트랜잭션 메모리
■ 스레드 수준 투기