Java 및 C #은 배열 범위 및 포인터 역 참조를 확인하여 메모리 안전성을 제공합니다.
경쟁 조건 및 교착 상태의 가능성을 방지하기 위해 프로그래밍 언어로 어떤 메커니즘을 구현할 수 있습니까?
Java 및 C #은 배열 범위 및 포인터 역 참조를 확인하여 메모리 안전성을 제공합니다.
경쟁 조건 및 교착 상태의 가능성을 방지하기 위해 프로그래밍 언어로 어떤 메커니즘을 구현할 수 있습니까?
답변:
레이스는 객체의 앨리어싱이 동시에 발생하고 하나 이상의 앨리어스가 변경되는 경우 발생합니다.
따라서 경쟁을 방지하려면 이러한 조건 중 하나 이상을 적용하지 않아야합니다.
다양한 접근 방식이 다양한 측면을 다룹니다. 함수형 프로그래밍은 불변성을 강조하여 불변성을 제거합니다. 잠금 / 원자는 동시성을 제거합니다. Affine 유형은 앨리어싱을 제거합니다 (변경 가능한 앨리어싱을 제거해야 함). 액터 모델은 일반적으로 앨리어싱을 제거합니다.
앨리어싱 할 수있는 개체를 제한하여 위의 조건을 피할 수 있습니다. 여기에서 채널 및 / 또는 메시지 전달 스타일이 나타납니다. 임의의 메모리를 별칭으로 지정할 수 없으며, 채널이나 대기열의 끝 부분에 레이스가 없어야합니다. 일반적으로 잠금 또는 원자와 같은 동시성을 피합니다.
이러한 다양한 메커니즘의 단점은 작성할 수있는 프로그램을 제한한다는 것입니다. 제한이 많을수록 프로그램이 줄어 듭니다. 따라서 앨리어싱이나 변경 작업이 없으며 추론하기 쉽지만 매우 제한적입니다.
그 때문에 Rust가 그러한 약동을 일으키고 있습니다. 앨리어싱과 변경 가능성을 지원하지만 동시에 발생하지 않는지 확인하는 컴파일러는 엔지니어링 언어입니다 (학술 언어와 반대). 이상적이지는 않지만 많은 이전 프로그램보다 더 큰 클래스의 프로그램을 안전하게 작성할 수 있습니다.
Java 및 C #은 배열 범위 및 포인터 역 참조를 확인하여 메모리 안전성을 제공합니다.
C #과 Java가이를 수행하는 방법에 대해 먼저 생각하는 것이 중요합니다. C 또는 C ++에서 정의되지 않은 동작을 정의 된 동작 으로 변환 하여이를 수행합니다 . 프로그램 충돌 . Null 역 참조 및 배열 인덱스 예외는 올바른 C # 또는 Java 프로그램에서 발견 되지 않아야 합니다. 프로그램에는 버그가 없어야하기 때문에 처음부터 발생하지 않아야합니다.
그러나 그것은 당신의 질문에 의해 당신이 의미하는 것이 아니라고 생각합니다! 우리는 서로 상호 대기하는 n 개의 스레드가 있는지 확인하고 그 경우 프로그램을 종료시키는 "데드락 안전"런타임을 쉽게 작성할 수 있지만, 그것이 당신을 만족시킬 것이라고 생각하지는 않습니다.
경쟁 조건 및 교착 상태의 가능성을 방지하기 위해 프로그래밍 언어로 어떤 메커니즘을 구현할 수 있습니까?
우리가 귀하의 질문에 직면하는 다음 문제는 교착 상태와 달리 "경주 조건"을 감지하기 어렵다는 것입니다. 스레드 안전에서 우리가 추구하는 것은 레이스를 제거 하지 않는다는 것을 기억하십시오 . 우리가 쫓는 것은 레이스에서 누가이기 든 프로그램을 올바르게 만드는 것입니다 ! 경쟁 조건의 문제는 두 개의 스레드가 정의되지 않은 순서로 실행되고 있으며 누가 먼저 완료할지 알 수 없다는 것입니다. 경쟁 조건의 문제점은 개발자가 일부 스레드 마무리 작업이 가능하다는 사실을 잊고 그 가능성을 설명하지 못한다는 것입니다.
따라서 귀하의 질문은 기본적으로 "프로그래밍 언어가 내 프로그램이 올바른지 확인할 수있는 방법이 있습니까?"로 요약됩니다. 그 질문에 대한 답은 실제로는 아닙니다.
지금까지 나는 당신의 질문을 비판했습니다. 여기서 기어를 바꾸고 질문의 정신을 다루겠습니다. 멀티 스레딩으로 인해 끔찍한 상황을 완화하기 위해 언어 디자이너가 선택할 수있는 선택이 있습니까?
상황은 정말 끔찍합니다! 특히 약한 메모리 모델 아키텍처에서 멀티 스레드 코드를 올바르게 얻는 것은 매우 어렵습니다. 어려운 이유에 대해 생각하는 것이 유익합니다.
언어 디자이너가 일을 개선 할 수있는 확실한 방법이 있습니다. 최신 프로세서의 성능을 포기하십시오 . 멀티 스레드 프로그램이라도 모든 프로그램이 매우 강력한 메모리 모델을 갖도록하십시오. 이것은 멀티 스레드 프로그램을 여러 번 더 느리게 만들게되는데, 이는 멀티 스레드 프로그램이 처음에있는 이유와는 반대로 성능 향상을 위해 직접 작동합니다.
메모리 모델을 떠나도 멀티 스레딩이 어려운 다른 이유가 있습니다.
그 마지막 요점에 대한 자세한 설명이 있습니다. "구성 가능"이란 다음을 의미합니다.
double이 주어진 int를 계산한다고 가정 해보십시오. 올바른 계산 구현을 작성합니다.
int F(double x) { correct implementation here }
int가 주어진 문자열을 계산한다고 가정 해보십시오.
string G(int y) { correct implementation here }
이제 double이 주어진 문자열을 계산하려면 다음을 수행하십시오.
double d = whatever;
string r = G(F(d));
G와 F는 더 복잡한 문제에 대한 올바른 솔루션 으로 구성 될 수 있습니다 .
그러나 교착 상태로 인해 잠금에이 속성이 없습니다. L1, L2 순서로 잠금을 수행하는 올바른 방법 M1 및 L2, L1 순서로 잠금을 수행하는 올바른 방법 M2를 모두 잘못된 프로그램을 작성하지 않고 동일한 프로그램에서 사용할 수 없습니다. 잠금은 "모든 개별 방법이 정확하므로 모든 것이 정확하다"고 말할 수 없도록합니다.
그렇다면 언어 디자이너로서 무엇을 할 수 있습니까?
먼저 가지 마세요. 하나의 프로그램에서 여러 개의 제어 스레드를 사용하는 것은 좋지 않으며 스레드간에 메모리를 공유하는 것은 나쁜 생각이므로 먼저 언어 나 런타임에 넣지 마십시오.
이것은 분명히 스타터가 아닙니다.
더 근본적인 질문으로 우리의 관심을 돌입시다. 왜 우리는 처음에 여러 스레드가 있습니까? 두 가지 주된 이유가 있으며, 비록 매우 다르지만 동일한 문제로 자주 뭉쳐집니다. 대기 시간 관리와 관련되어 있기 때문에 혼란스러워합니다.
나쁜 생각. 대신 코 루틴을 통해 단일 스레드 비동기를 사용하십시오. C #은 이것을 아름답게합니다. Java는 잘되지 않습니다. 그러나 이것이 현재 언어 디자이너가 스레딩 문제를 해결하는 데 도움을주는 주요 방법입니다. await
C # 의 연산자 (F # 비동기 워크 플로 및 기타 선행 기술에서 영감을 받음)는 점점 더 많은 언어로 통합되고 있습니다.
언어 디자이너는 병렬 처리에 적합한 언어 기능을 만들어 도움을 줄 수 있습니다. 예를 들어 LINQ가 어떻게 자연스럽게 PLINQ로 확장되는지 생각해보십시오. 당신이 현명한 사람이고 TPL 작업을 매우 병렬적이고 메모리를 공유하지 않는 CPU 바운드 작업으로 제한하면 여기서 큰 승리를 얻을 수 있습니다.
우리는 무엇을 더 할 수 있습니까?
C #에서는 교착 상태에 대한 레시피이므로 잠금 상태에서 기다릴 수 없습니다. C #에서는 항상 잘못된 행동을하기 때문에 값 유형을 고정 할 수 없습니다. 값이 아닌 상자를 잠그십시오. 별칭이 습득 / 릴리스 의미를 부과하지 않기 때문에 C #에서 휘발성 별칭을 지정하면 경고합니다. 컴파일러가 일반적인 문제를 감지하고 방지 할 수있는 더 많은 방법이 있습니다.
C #과 Java는 참조 객체를 모니터로 사용할 수있게하여 큰 디자인 오류를 일으켰습니다. 따라서 교착 상태를 추적하기가 어려워지고 정적으로 방지하기가 어려워지는 모든 종류의 나쁜 습관이 권장됩니다. 그리고 모든 객체 헤더에서 바이트를 낭비합니다. 모니터는 모니터 클래스에서 파생되어야합니다.
STM은 훌륭한 아이디어이며, Haskell에서 장난감 구현을 가지고 놀았습니다. 잠금 기반 솔루션보다 올바른 부품으로 올바른 솔루션을 훨씬 더 우아하게 작성할 수 있습니다. 그러나 나는 왜 대규모로 작동하지 못했는지에 대한 세부 사항에 대해 충분히 알지 못합니다. 다음에 조 더피에게 물어봐
프로세스 미적분학 기반 언어에 대한 많은 연구가 있었고 그 공간을 잘 이해하지 못합니다. 그것에 대한 몇 가지 논문을 직접 읽어보고 통찰력이 있는지 확인하십시오.
Roslyn에서 Microsoft에서 근무한 후 Coverity에서 근무했으며 Roslyn을 사용하여 분석기 프런트 엔드를 얻는 것이 었습니다. Microsoft가 제공하는 정확한 어휘, 구문 및 의미 분석을 통해 일반적인 멀티 스레딩 문제를 발견 한 탐지기 작성에 집중할 수있었습니다.
우리가 인종과 교착 상태와 그 모든 것들을 가지고있는 근본적인 이유는 우리가 해야 할 일을하는 프로그램을 작성하고 있기 때문에 명령형 프로그램을 작성하는 데는 모두 헛된 것입니다. 컴퓨터는 사용자가 말한 것을 수행하며 잘못된 일을하도록 지시합니다. 현대의 많은 프로그래밍 언어는 선언적 프로그래밍에 관한 것입니다. 원하는 결과를 말하고 컴파일러가 그 결과를 달성 할 수있는 효율적이고 안전하며 올바른 방법을 찾도록하십시오. LINQ를 다시 생각해보십시오. 우리는 당신이 의도from c in customers select c.FirstName
를 표현하는 말을 원합니다 . 컴파일러가 코드 작성 방법을 알아 내도록하십시오.
기계 학습 알고리즘은 수작업으로 코딩 된 알고리즘보다 일부 작업에서 훨씬 나아지지만 물론 정확성, 훈련 시간, 나쁜 훈련으로 인한 편견 등 많은 상충 관계가 있습니다. 그러나 현재 우리가 "수작업으로"코딩하는 많은 작업이 머지 않아 기계 생성 솔루션에 적용될 수있을 것입니다. 인간이 코드를 작성하지 않으면 버그를 작성하지 않은 것입니다.
죄송합니다. 조금 엉망이었습니다. 이것은 거대하고 어려운 주제이며 20 년 동안이 문제 영역에서 진보 해 온 PL 커뮤니티에서 명확한 합의가 이루어지지 않았습니다.