또한 레이스 컨디션은 프로그램 코드상의 더 높은 수준의 디자인 문제가 원인임을 나타낼 수도 있습니다. 간단하고 실제로 사용되는 병렬 프로그램을 이용해서 다양한 레이스 컨디션 문제들을 알아보고 어떻게 극복할 수 있는지에 관해서도 알아 봅니다.
소개
병렬 프로그램은 소프트웨어 개발자에게 쉬운 작업이 절대 아닙니다. 대부분의 소프트웨어 개발자들은 단 하나의 순차적인 작업 플로우를 가진 코드를 작성하도록 훈련되어 왔습니다. 병렬 프로그램에서 개발자들은 복수개의 플로우를 가진 동시다발적인 작업을 수행하는 코드를 디자인하고 작성하기 위한 새로운 관점을 취할 필요가 있습니다. 병렬 소프트웨어 패러다임을 처음 접하는 개발자들에게 가장 어려운 문제는 병렬 프로그래밍의 가장 기본적인 문제 입니다: 레이스 컨디션(race conditions) 이라고 알려진 신드롬. 레이스 컨디션은 비동기화된 동시다발적인 실행으로 인해 예측할 수 없는 프로그램 상태와 행동을 유발하는 프로그래밍 오류 입니다. 레이스 컨디션은 회피하기 상당히 어렵고 또한 일반적인 디버깅 방법과 툴들로 찾기 매우 힘듭니다. 더더욱 어려운 것은 레이스 컨디션에는 수많은 미묘한 측면들이 있습니다. 개발자들은 위험한 병렬 프로그래밍 구역에 들어서기 전에 이러한 지뢰들에 대해 잘 알고 있는것이 중요 합니다.
가장 자주 접하는 레이스 컨디션은 데이타 레이스 컨디션 입니다. 데이타 레이스 컨디션은 복수개의 쓰레드에서 동일한 메모리 무질서한 접근에 의해 발생 됩니다. 자주 발생하진 않지만 찾기에는 더 힘든 일반적인 레이스 컨디션도 있습니다. 잡아내기 어려운 일반적인 레이스 컨디션은 종종 일시적인 전환 상태에서 데이타 충돌을 유발하는 복수개의 병행 이벤트들의 실행 순서에 의해 프로그램의 실행이 애매모호해지는 현상 때문에 발생 합니다.
그러나 모든 레이스 컨디션이 모두 프로그래밍 버그 인것은 아닙니다. 그리고 몇몇 데이타 레이스 컨디션은 유해하지도 않습니다. 퍼포먼스 때문에 병렬 프로그램에서 레이스 컨디션을 용납하는 경우도 있습니다. 마지막으로 아주 중요한 것은 레이스컨디션은 프로그램 코드의 잘못된 로직이나 잘못된 프로그래밍 스타일에 의한 좀 더 깊숙한 다지안 문제의 현상일 수도 있다는 것입니다. 이러한 어려운 문제들은 실제 프로그램을 가지고 토론하는 것이 더 쉬울 것입니다. 이 글에서는 간단하고 널리 쓰이는 병렬 파티셔닝 프로그램 예제를 이용해서 위의 다양한 레이스 컨디션 이슈들에 대해 설명 합니다.
파티셔닝 프로그램 예제
각각의 작업 쓰레드는 오브젝트 배열을 순회하면서 오브젝트들 중에서 적절한 속성을 가진 것들을 선택하고 이것을 그룹 컨테이너에 저장할 것입니다. 또한 각각의 작업 쓰레드는 그룹 컨테이너의 저장된 오브젝트들을 카운트 해서 글로벌 전체 카운트에 더해 줍니다. 마지막으로 전체 카운트가 입력 오브젝트 카운트와 동일한지 확인해서 파티셔닝 작업동안 어떠한 오브젝트가 수집되지 않았는지 확인합니다.
partition_main.cpp
| 1. // global declaration 2. #include <stdio.h> 3. #include <math.h> 4. #include <pthread.h> 5. #include "element.h" 6. #include "container.h" 7. #define NGRPS 30 8. 9. int object_count = 0; 10. element* object_array; 11. container group_array[NGRPS]; 12. int total_count = 0; 13. 14. void* collect(void* arg) 15. { 16. int j; 17. 18. int group_id = *((int *) arg); 19. int group_count = 0; 20. 21. attribute group_attribute = get_group_attribute(group_id); 22. container group_container = group_array[group_id]; 23. for (j = 0; j < object_count; j++) { 24. element current_object = object_array[j]; 25. if (current_object.collectFlag == true) continue; // this flag is initialized to false 26. if (current_object.matchAttribute( group_attribute)) { 27. current_object.collectFlag = true; 28. group_container.add( current_object); 29. group_count++; 30. } 31. } 32. total_count += group_count; 33. return NULL; 34. } 35. 36. 37. int main(int argc, char** argv) 38. { 39. int i; 40. pthread_t pids[NTHRS -1]; 41. 42. object_count = process_input_data(argv[1], &object_array); 43. 44. for (i = 0; i < NTHRS; i++) { 45. pthread_create(&pids[i], NILL, collect, (void*) &i); 46. } 47. 48. if (total_count != object_count) { 49. printf(" the collected object count %d doesn't match the original object count %d\n", 50. total_count, object_count); 51. } 52. } |
데이타 레이스 컨디션 문제
데이타 레이스 컨디션 문제는 Pthreads와 OpenMP 같은 공유 메모리 병렬 프로그래밍 모델에서 자주 발생 합니다. 데이타 레이스 컨디션 는 복수개의 쓰레드가 공유 메모리를 무질서한 순서대로 접근 하고 적어도 하나의 접근이 새로운 데이타를 공유 메모리 장소에 쓰려고 할때 발생합니다.파티션 프로그램 예제에서 데이타 레이스 문제는 32번째 줄에서 발생합니다: collect 루틴의
total_count += group_count. total_count 는 글로벌 정적 변수로 모든 취합 작업 쓰레드에 의해 공유 됩니다. 쓰레드가 전체 카운트의 값을 읽고 그룹 카운트 값을 토탈 카운트에 더하려고 할 때 다른 쓰레드가 작업 중간에 끼어들 수 있고 동시에 전체 카운트의 예전 값을 읽을 수 있습니다. 첫번째 쓰레드가 전체 값에 새로운 값을 쓴 바로 다음에 두번째가 이 값을 고유의 새로운 값으로 덮어 써서 첫번째 쓰레드의 노력을 날려 버릴 수 있습니다. 이러한 데이타 레이스 문제의 영향은 예측 불가능하고 수백개의 쓰레드가 실행될때에만 발생할 수도 있습니다. 데이타 레이스 컨디션 문제는 종종 잘못된 포인터에 의해 발생하는 문제보다 훨씬 디버깅 하기가 어렵습니다. 잘못된 포인터는 일반적으로 잘못된 영역을 가르키고 단순히 세그먼테이션 폴트를 유발 합니다.
그러나 데이타 레이스 컨디션은 예측못한 방법으로 중요한 변수의 값을 잘못 생성하고 프로그래머가 프로그램의 동작에 대해 혼동하도록 합니다. (데이타 레이스 컨디션은 MPI 어플리케이션 같은 분산 메모리 병렬 프로그램에서는 발생하지 않습니다) 멀티 쓰레드 프로그래밍에서 글로벌 변수의 사용 혹은 접근을 제한 하는 것이 매우 중요 합니다.
데이타 레이스 컨디션 시작하기
모든 데이타 레이스 컨디션이 유해한 것은 아닙니다. 위의 파티셔닝 예제에서 collect 루틴에 또다른 데이타 레이스가 존재 합니다. 두번째 데이타 레이스는 collect 루틴의 25 와 27번째 줄에서 발생합니다.25번째 줄에서 작업 쓰레드는 현재 오브젝트의
collect_flag 를 확인하고 현재 오브젝트에 대한 작업을 계속할지를 확인합니다. 27번째 줄에서 작업 쓰레드는 오브젝트의 속성이 그룹 속성과 일치할 때 현재 오브젝트의 collect 플래그를 on 할 것이고 이 오브젝트는 그룹 컨테이너에 저장될 것입니다. 데이타 레이스 컨디션은 복수개의 쓰레드가 동일한 현재 오브젝트를 처리할때 발생하며 동일 오브젝트의 collect_flag 필드를 무질서한 순서로 읽고 쓰기를 반복할 것입니다.만약 파티셔닝 예제에서 모든 오브젝트의 속성이 오직 하나의 그룹 속성과 일치한다면 데이타 레이스 컨디션이 시작되지만 어떠한 유해한 결과도 유발하지는 않을 것입니다. 사실 이것은 병렬 프로그램이 더 빠르게 동작하도록 할 것입니다. 왜냐하면 현재 오브젝트가 다른 그룹에 속해 있을때 같은 불필요한 매치 작업이 제거될 것이기 때문입니다. 두번째 데이타 레이스 컨디션은 오직 두번째 데이타 레이스 컨디션은 오직 중복의 매치 작업을 제거하는 작업의 효율성에만 영향을 미칩니다.
그러나 만약 오브젝트가 복수개의 그룹에 속할 수 있다면 이 데이타 레이스 컨디션은 실제로 문제가 되고 유해한 결과를 유발할 것입니다. 하나의 쓰레드가 현재 오브젝트가 그에 속한 것으로 확인 하고 오브젝트의
collect_flag 플래그를 온시키는 도중에 다른 쓰레드가 동일한 오브젝트의 collect_flag 를 체크하고 동시에오브젝트가 어떠한 그룹에도 속해 있지 않음을 확인 할 수도 있을 것입니다. 그러므로 오브젝트는 collect_flag 의 접근 순서에 따라서 하나 혹은 복수개의 그룹에 저장될 수도 있을 것입니다.공유 메모리 병렬 프로그래밍 모델에서 쓰레드는 반드시 다른 쓰레드들 간에 중요한 데이타를 이용해 통신해야 합니다. 이론적으로 모든 쓰레드는 현재 전체 프로그램의 상태를 알기 위해서 이 중요한 값을 읽어야 하고 이후의 작업을 결정해야 합니다. 적어도 하나의 쓰레드는 중요 데이타에 새로운 값을 넣거나 수정해야할 필요가 있습니다. 이러한 종류의 체크 및 업데이트 패턴은 병렬 프로그램에서는 아주 일반적이지만 본질적으로 데이타 레이스 컨디션을 유발할 수 있습니다.
만약 모든 수정 작업들이 취소되야 하고 참여하고 있는 모든 쓰레드들이 동기화 되어야 한다면, 병렬 컴퓨팅의 효율성이 아주 심각하게 떨어질 것입니다. 그러므로 데이타 레이스는 많은 경우에 필요한 하나의 타협입니다. 유익한 그리고 유해한 레이스 컨디션의 구분은 매우 애매 모호하고 입력 셋과 프로그램의 실행 조건에 따라 달라 집니다. 오직 그들의 프로그램을 이해하는 프로그래머만이 데이타 레이스의 유해성을 판단할 수 있습니다.
일반적인 레이스 컨디션(General Race Condition)
일반적인 레이스 컨디션 은 프로그램의 실행 무결성을 위반하는 애매모호한 실행 순서와 단일 메모리 장소 접근으로 귀착되지는 못하는 것에 의해 발생 합니다. (Wisconsin 대학의 Robert H.B. Netzer 와 Barton P. Miller 는 일반적인 레이스 컨디션에 대한 공식적인 정의를 내렸습니다) 데이타 레이스 컨디션은 일반적인 레이스 컨디션의 하나의 형태 입니다. 이 글을 통틀어서 일반적인 레이스 컨디션이란 단어의 뜻은 데이타 레이스 종류가 아닌 레이스 컨디션을 의미 합니다. 일반적인 레이스 컨디션은 데이타 레이스 컨디션보다 알아내기 훨씬 힘듭니다. 일반적인 레이스 컨디션의 본질적인 어려움은 많은 컴퓨터 과학 연구자들이 트랜젝션이 가능한 메모리 접근에 대해 연구하도록 하였습니다. 트랜젝션이 가능한 메모리의 기본적인 개념은 데이타베이스 트랜젝션의 개념을 병렬 프로그래밍의 일반적인 문제들을 해결하기 위해 함으로써 여전히 멀티 프로세서 머신에서 병렬 퍼포먼스를 내도록 하는 것입니다.
여기서 우리는 파티션 프로그램을 일반적인 레이스 문제를 보여주독 하기 위해 확장하도록 하겠습니다. 취합의 첫번째 단계 이후에 파티셔닝 프로그램이 아래의 코드 처럼 몇몇 오브젝트들을 미세하게 조정하고 섞어서 하나의 그룹 컨테이너에서 다른 그룹 컨테이너로 옮기도록 해보겠습니다.
- partition_shuffle.cpp
| 1. void shuffle_objects( container* source, container* destination, element* target_objects ) { 2. 3. // remove target objects from source container 4. mutex_lock(); 5. source.remove_array( target_objects ); 6. mutex_unlock(); 7. 8. // Here is a transitory state which may cause general race condition 9. 10. // add target objects to source container 11. mutex_lock(); 12. destination.add_array( target_objects); 13. mutex_unlock(); 14. } |
위의 프로그램은 아주 깨끗하고 간단한 것처럼 보입니다. 두개의 컨테이너
remove_array 와 add_array 메소드가 락에 의해 보호되기 때문에 데이타 레이스 컨디션은 발생하지 않을 것입니다. 그러나 일반적인 레이스는 전환상태에서 발생할 수 있는데, 코드의 8번째 줄에서, 두 그룹 컨테이너의 제거와 추가 작업 사이에서 발생할 수 있습니다. 만약 오브젝트들에 병렬로 작업하고 있는 다른 쓰레드가 존재 한다면 대상 오브젝트를 미스(miss)할 수도 있습니다. 왜냐하면 결정적인 순간에 대상 오브젝트들의 소속이 없을 수도 있기 때문입니다. 이러한 상황에 대한 예를 설명하도록 해보겠습니다. 오브젝트 섞기가 5개의 독립적인 규칙에 의해 수행된다고 가정해 봅시다. 이것은 자연적으로 5개의 쓰레드를 생성하고 각각의 쓰레드가 하나의 룰을 기반으로 동시에 실행될 것입니다. 일반적인 레이스 컨디션은 대상 오브젝트가 쓰레드 1에 의한 섞기 작업 때문에 발생하는 전환 상태에 의해 쓰레드 2가 대상 오브젝트를 미스 하면서 발생 합니다.
직관적인 해결책은 전체 shuffle_objects 메소드를 값비싼 원자적인(atomic) pragma 로 묶어서 다른 쓰레드 혹은 프로세스가 작업의 중간에 끼어드는 것을 방지하는 것입니다. 그러니 이 해결책은 몇몇 어플리케이션 파티셔닝 요구조건에 맞는 해결책은 아닐 것입니다. 예를 들어 만약 파티셔닝 프로그램이 전자 부품 오브젝트들을 다루고 있고 그들의 자식 핀 오브젝트들을 다루어야 하고, 전자 부품과 그들의 핀들의 그룹핑 작업이 반드시 그들의 부모 부품들과 핀 오브젝트들을 일관적인 상태로 유지해야 하도록 원자적으로 작업이 되어야 할 때 같은 경우를 들 수 있습니다. 다시한번 말해서 아래의 프로그램코드는 25번째 줄에서 일반적인 레이스 컨디션 오류를 유발할 수 있는 전환 상태를 보여 줍니다.
partition_shuffle.cpp (계속)
| 20. void shuffle_components(container* component_source, container* component_destination, 21. elements* target_components) 22. { 23. 24. shuffle_objects(component_source, component_destination, target_components); 25. // Here is another transitory state which may cause general race condition 26. pins* target_pins = get_child_pins(target_components); 27. container* pin_source = get_pin_container( component_source); 28. container* pin_destination = get_pin_container(component_destination); 29. shuffle_objects(pin_source, pin_destination, target_pins); 30. } |
이 새로운 문제에 대한 해결책은 전체
shuffle_components 메소드를 원자적인 트랜젝션으로 묶는 것입니다. 그러므로 원자적인 트랜젝션 타입 요구사항은 꽤 긴 작업 순서에 노출 되어야 할 것입니다. 그러나 작업들의 원자적인 트랜젝션이 길어지고 복잡해 진다면 병렬 프로그래밍의 본래 목적을 벗어나게 됩니다. 일반적으로 일반적인 레이스는 첫번째로 피하기 어렵고 또한 문제를 발견하더라도 수정하기가 매우 어렵습니다. 게다가 일반적인 레이스 컨디션은 MPI 나 공유 메모리 같은 분산 메모리 병렬 모델에서도 발생할 수 있습니다.일반적인 레이스 컨디션의 큰 장애물은 병렬 프로그래밍에 대한 중요한 디자인 교훈을 알려 줍니다. 개발자는 프로그램의 상태들, 데이타 의존성 뿐만 아니라 상태 변환에도 집중해야 합니다. 각각의 작업 단계동안에 내부 프로그램의 상태를 검증할 수 있는 보조 메소드를 구현하는 것이 항상 도움이 됩니다.
레이스 컨디션 문제의 실제 원인 이해하기
파티셔닝 예제 프로그램의 collect 루틴으로 되돌아 가 봅시다. collect 루틴에서는 3번째 데이타 레이스 문제가 존재 합니다. 이 데이타 레이스 문제는 매우 찾아내기 어렵고 신중한 조사 없이는 이해하기 매우 힘듭니다. collect 루틴의 28번째 줄에서 group_container.add(current_object) 구믄은 고유의 데이타 레이스 컨디션 문제를 가지고 있습니다. 코드를 보는 것 만으로는 데이타 레이스 문제를 찾기가 쉽지 않습니다. 사실 이 데이타 레이스 문제는 다른 데이타 레이스 문제에 의해 유발되는데, 이러한 간단한 프로그램에도 벌써 4개의 데이타 레이스 문제가 존재 합니다! 이 파티셔닝 프로그램에서의 4번째 데이타 레이스 문제는 설명하기 쉽습니다. 18번째 줄에서 각각의 쓰레드의 그룹 ID 는 루틴 매개 변수 arg 에 의해 건네지고 이것은 메인 프로그램의 루프 인덱스 i 의 주소를 통해서 전달 됩니다. 메인 쓰레드 프로그램은 44번째 줄에서 루프 인덱서 i 까지 진행되고 arg 에 의해 가르켜지는 메모리 장소에 새로운 값을 씁니다. 그러므로 이 메모리 장소를 읽고 작업 쓰레드가 이것을 그룹 ID 로 변환 하고 (18번째 줄), 메인 쓰레드에 의해 새로운 루프 인덱스 값이 쓰여지는(44번째 줄) 동안에 데이타 레이스 컨디션이 존재 합니다.
이 데이타 레이스 컨디션이 발생되면 두개의 서로 다른 작업 쓰레드가 동일한 그룹 ID 로 지정되고 28번째 줄에서 데이타 레이스 컨디션을 유발할 것입니다. 그러나 이 두개의 데이타 레이스 컨디션의 진짜 원인은 45번과 18번째 줄의 올바르지 않은 코딩 스타일 때문입니다. 항상 데이타의 포인터 대신에 데이타 값을 전달해야 합니다.
파티셔닝 프로그램을 OpenMP 를 이용해서 구현했다면 3번째와 4번째 데이타 레이스 컨디션은 발생하지 않았을 것입니다. OpenMP 같은 고수준의 프로그래밍 모델은 이러한 구현 버그들의 위험성을 줄여 줍니다. 만약 여러분의 멀티쓰레드 프로그램이 OpenMP 로 구현될 수 있다면 반드시 사용을 고려하시기 바랍니다. OpenMP 로 이 파티셔닝 프로그램을 구현했다면 좀 더 안전하고 효율 적이였을 것입니다.
아래는 파티셔닝 프로그램을 OpenMP 로 구현한 것입니다. collect 루틴의 입력 매개변수 타입이 더이상
void* 포인터 타입으로 제한되지 않음으로써 입력 매개변수를 정수 타입으로 정의하고 루프 인덱스 값을 메인 프로그램으로 부터 그룹 ID 로 취합니다. collect 루틴의 리턴 타입 또한 제한되지 않습니다. 리턴 값은 정수 타입으로 정의 되었고 취합된 그룹 카운트는 메인 프로그램이 리턴 됩니다. OpenMP 프로그램은 좀 더 안전하고 구현하기도 좀 더 쉽고 또한 Pthread 프로그램 보다 이해하기 쉽습니다.partition_omp.cpp
| 1. // global declaration 2. #include <stdio.h> 3. #include <math.h> 4. #include <omp.h> 5. #include "element.h" 6. #include "container.h" 7. #define NGRPS 30 8. 9. int object_count = 0; 10. element* object_array; 11. container group_array[NGRPS]; 12. int total_count = 0; 13. 14. int collect(int group_id) // return the collected group count 15. { 16. int j; 17. int group_count = 0; 18. 19. attribute group_attribute = get_group_attribute(group_id); 20. container group_container = group_array[group_id]; 21. for (j = 0; j < object_count; j++) { 22. element current_object = object_array[j]; 23. if (current_object.collectFlag == true) continue; // this flag is initialized to false 24. if (current_object.matchAttribute( group_attribute)) { 25. current_object.collectFlag = true; 26. group_container.add( current_object); 27. group_count++; 28. } 29. } 30. return group_count; 31. } 32. 33. 34. int main(int argc, char** argv) 35. { 36. int i; 37. #ifdef _OPENMP 38. omp_set_num_threads( NTHRS ); 39. omp_set_dynamic(0); 40. #endif 41. 42. object_count = process_input_data(argv[1], &object_array); 43. 44. #pragma omp parallel for 45. for (i = 0; i < NTHRS; i++) { 46. total_count += collect( i ); 47. } 48. 49. if (total_count != object_count) { 50. printf(" the collected object count %d doesn't match the original object count %d\n", 50. total_count, object_count); 51. } 52. } |
요약
병렬 프로그램은 대부분의 소프트웨어 개발자에게 새로운 세계 입니다. 현재의 처리량(throughput) 컴퓨팅 트렌드의 멀티-코어 프로세스 기술은 많은 소프트웨어 개발자들이 병렬 프로그래밍을 강요하고 있습니다. 운나쁘게도 병렬 소프트웨어 개발의 어려움은 순차적인 소프트웨어 개발 보다 몇단계 더 어렵습니다. 병렬 프로그래밍에는 더 다양한 디자인 이슈들이 존재 합니다. 그럼에도 불구하고 레이스 컨디션은 개발자가 접하는 가장 기본적인 문제입니다. 이 글에서 우리는 개발자가 배워야할 그리고 병렬 소프트웨어 디자인시에 피해야할 다양한 레이스 컨디션 이슈들에 대해 다루었습니다.
소프트웨어 개발은 적절한 툴의 셋을 사용할 것을 요구 합니다. 그리고 병렬 소프트웨어서는 특히 더 그렇습니다. 이 글에서의 병렬 프로그램 분석을 통해서 툴이 레이스 컨디션을 쉽게 찾아낼 수 있는 툴이 필요한지를 잘 알 수 있습니다. 아직 까지는 일반적인 레이스 컨디션을 다룰 수 있는 개발자 툴이 존재하지는 않습니다. 그리고 복잡한 프로그램의 특성상 이러한 툴이 존재할 수 있는지에 대해서도 의문 입니다. 그러므로 많은 컴퓨터 과학 연구자들은 트랜젝션적인 메모리 접근을 지지하고 있습니다.
어쨌든 데이타 레이스 컨디션 문제를 다루기 위한 몇가지 툴들이 현재 존재 합니다. 썬이 배포하고 있는 썬 스튜디오 익스프레스의 데이타 레이스 감지 툴 이 바로 그러한 툴이고 인텔의 쓰레드 체커, 오픈소스 Valgrind 의 Helgrind 등이 바로 그것입니다.
훌륭한 질의 소프트웨어를 디자인하는 것은 절대적으로 프로그램의 지식과 경험에 달려 있고 또한 적절한 툴 사용에도 잘려 있습니다. 레이스 컨디션 문제들을 회피할 수 있는 레슨들이 몇가지 있는데 아래에 이러한 것들이 요약 되어 있습니다:
- 레이스 컨디션을 유발하는 장황한 구현의 위험을 줄여줄 수 있는 OpenMP 같은 고급 디자인 추상 모델을 수용한다.
- 포인터에의한전달 대신 데이타값에의한전달을 이용하여 쓰레드와 프로세스들 간 통신하기.
- 글로벌 변수의 사용을 제한하는 데이타구조 디자인 및 복수개 쓰레드의 공유 변수 접근 금지하기.
- 프로그램 상태 및 입력 셋, 런타임 환경을 분석하여 레이스 컨디션이 실제 프로그램 버그인지를 확인하기. 이러한 방법을 통해 더 나은 퍼포먼스를 얻을 수 있음.
- 레이스 컨디션의 실제 원인을 분석. 레이스 컨디션의 해결 대신에 실제 프로그램 버그의 수정에 집중함.
- 프로그램의 실행 상태와 상태 전환에 대해 완전히 이해 하기. 쓰레드 혹은 프로세스가 몇몇 프로그램 오브젝트에 의해 상태 전환이 유발될때, 다른 병행 쓰레드 혹은 프로세스가 동일한 오브젝트에 병렬로 접근하는 것을 방지함.
- 프로그램의 각각의 작업 단계마다 프로그램의 상태 무결성을 확인할 수 있는 내부 상태 체크 메카니즘을 구현.
참고자료
- "Parallel Programming Introduction", http://www.mhpcc.edu/training/workshop/ ··· ain.html
- "POSIX Threads Programming", http://www.llnl.gov/computing/tutorials/pthreads
- "OpenMP home page", http://www.openmp.org
- "The Message Passing Interface (MPI) standard", http://www-unix.mcs.anl.gov/mpi/
- "Open MPI: Open Source High Performance Computing",http://www.open-mpi.org/
- "What are Race Conditions? Some Issues and Formalization", Robert H.B. Netzer and Barton P. Miller, In ACM Letters on Programming Languages and Systems, Vol. 1 No. 1 March 1992
- "Transactional Memory Online", http://www.cs.wisc.edu/trans-memory/
- "Transactional Memory Coherence and Consistence", Lance Hammond, Vicky Wong, Mike Chen, Brian D. Carlstrom, John D. Davis, Ben Hertzberg, Manohar K. Prahu, Honggo Wijaya, Christos Kozyrakis and Kunle Olukotun, http://ogun.stanford.edu/~kunle/publications/tcc_stmcs2006.pdf
- "OpenMP Parallelization Pragmas for C and C++", http://www.tacc.utexas.edu/services/use ··· 2u12.htm
- "Throughput Computing Main Page", http://www.sun.com/processors/throughput/
- "Developing Applications For Parallel Computing", Liang T. Chen, http://developers.sun.com/solaris/articles/parallel.html
- "Sun Studio Express: Data Race Detection Tool", http://developers.sun.com/sunstudio/downloads/drdt/drdt_index.html
- "Intel Threading Tools",http://www.intel.com/cd/software/produc ··· ndex.htm
- "Valgrind's Tool Suite", http://valgrind.org/info/tools.html
감사의 인사
필자는 이 글에 영감을 준 데이타 레이스 감지 툴 프로젝트에 참여하고있는 같은 썬 동료들에게 감사의 인사를 전합니다. 이글에서 언급된 몇몇 데이타 레이스 컨디션들은 DRDT 테스팅에서 발견된 실제 문제들에서 취해졌습니다. 또한 초기 드래프트를 리뷰해준 아들 David Chen 과 썬 동료들 Yuan Lin 과 Vijay Tatkar 에게 감사의 인사를 전합니다.
이 글의 영문 원본은
The Challenge of Race Conditions in Parallel Programming
에서 보실 수 있습니다.
"개발자코너" 카테고리의 다른 글
- 솔라리스상에서 PHP 를 이용한 웹 어플리케이션 작성 (댓글 0개 / 트랙백 0개) 2008/07/17
- 솔라리스 SPARC 플랫폼, x86 플랫폼 간의 컴파일러 차이점 (댓글 28개 / 트랙백 3개) 2007/09/17
- 쉘 프로그래밍 기법 (댓글 1개 / 트랙백 0개) 2005/09/23
- Solaris OS, SPARC Platform Edition에서 x86 Platfo... (댓글 1개 / 트랙백 0개) 2005/10/23
- libumem 라이브러리를 이용하여 어플리케이션 내의 메모리 관리 버그를 잡아 내는 방법 (댓글 1개 / 트랙백 1개) 2006/03/23
- 스토리지 유틸리티 실습: ZFS 스냅샷과 Amazon S3 연동 (댓글 0개 / 트랙백 1개) 2008/04/17
- 썬 스튜디오: VIS 명령을 사용하여 중요한 루틴의 속도를 향상시키기 (댓글 1개 / 트랙백 0개) 2006/02/23
- 병렬 프로그래밍 단어 총정리 (댓글 22개 / 트랙백 3개) 2007/09/17
- 병렬 컴퓨팅을 위한 어플리케이션 개발 (댓글 0개 / 트랙백 2개) 2007/12/14
- DTrace를 사용하여 유저가 조정하는 애플리케이션 크래쉬 데이타 정보 모으기 (댓글 1개 / 트랙백 0개) 2006/08/23
댓글을 달아 주세요