나는 비동기식으로 응용 프로그램 (Win64, C++)을 향상시키고 있습니다. 동시성 런타임 (Concurrency Runtime)을 사용하고 있으며 지금까지 저에게 큰 도움이되었습니다.동시성 런타임에 대한 작업 로컬 변수 구현
기본적으로 응용 프로그램은 여러 가지 '작업'변환 데이터를 실행합니다. 각 작업이 수행하는 작업을 추적하기 위해 특정 하위 시스템에는 작업이 수행하는 특정 작업을 추적하는 코드가 설치되어 있습니다. 이전에는 컨텍스트 정보를 호출 체인 전체로 전달하지 않고 추적 정보를 등록 할 수 있도록 현재 실행중인 작업을 나타내는 단일 전역 변수를 사용했습니다. 각 작업은 작업 자체를 병렬화하기 위해 ConcRT를 사용할 수도 있습니다. 이것은 모두 잘 작동합니다.
이제 최상위 작업을 병렬로 실행할 수 있도록 응용 프로그램을 리팩토링하고 있습니다. 각 작업은 ConcRT 작업으로 실행되며 이는 추적이 필요한 작업을 제외한 모든 작업에 적합합니다.
기본적으로 필요한 것은 작업과 컨텍스트 정보를 연결하고 해당 작업에 의해 생성 된 다른 작업에 대한 흐름을 유지하는 방법입니다. 기본적으로 "작업 로컬"변수가 필요합니다.
ConcRT를 사용하면 컨텍스트 정보를 저장하기 위해 단순히 스레드 로컬을 사용할 수 없습니다. 작업이 ConcRT를 사용하는 다른 작업을 생성 할 수 있고 모든 스레드에서 실행되기 때문입니다.
현재 나의 접근 방식은 시작시 여러 개의 Scheduler 인스턴스를 생성하고 각 작업을 해당 작업 전용의 스케줄러에 생성하는 것을 포함합니다. 그런 다음 Concurrency::CurrentScheduler::Id()
함수를 사용하여 문맥을 파악하는 데 사용할 수있는 정수 ID를 검색 할 수 있습니다. 이 작업은 가능하지만 어셈블리에서 Concurrency::CurrentScheduler::Id()
을 한 번 밟아 보면 여러 가상 함수 호출과 안전성 검사를 수행하기 때문에 약간의 오버 헤드가 발생합니다.이 조회는 극도의 작업이 필요하기 때문에 조금 문제가됩니다. 어떤 경우에는 높은 비율.
이렇게하려면 더 좋은 방법이 있습니까? 나는 약간의 오버 헤드로 검색 할 수있는 현재 Scheduler/SchedulerGroup/Task와 단일 컨텍스트 포인터를 연관시킬 수있는 일류 TaskLocal/userdata 메커니즘을 가지고있는 것을 좋아했을 것입니다.
ConcurT 스레드가 새 작업을 잡을 때마다 호출되는 후크가 스케쥴러/ScheduleGroup ID를 검색하여 최소 액세스 오버 헤드를 위해 로컬 스레드에 저장할 수 있기 때문에 이상적입니다. 아아, 그런 훅을 등록 할 수있는 방법이 없으며 PPL/에이전트 용 사용자 정의 스케줄러 클래스를 구현할 수없는 것 같습니다 (this article 참조).
그렇습니다. 명백한 해결책이며, 이는 기본적으로 대부분의 코드에서 수행합니다. 그러나 코드의 하위 집합에 대해서는 과도한 상세 표시로 이어질 수 있으므로 옵션이 아닙니다. 기본적으로 setters/getters가있는 코드 생성 데이터 객체 클래스가 있습니다. 게터는 데이터 의존성을 추적하기 위해 사용 된 것을 등록하도록 선택적으로 계측 할 수 있습니다. 컨텍스트 객체를이 모든 getter에 전달하고 컨텍스트를 모든 호출 체인에서 처리해야하는 것은 매우 어색합니다. 기본적으로 스케줄러 ID를 사용하여 스케줄러 로컬 변수를 구현하면 좋은 성능으로 작동합니다. –
@StefanBoberg : 싱글 톤이 아닌 싱글 톤을위한 대체 모델이 있습니다. 그것은 당신이 값을 '쌓아 올리는'것을 허락합니다. 새 값을 스택에 푸시 (push) 할 수 있으며 값이 팝되고 이전 값이 복원 될 때까지는 싱글 톤 값이됩니다. 이 변수의 부모 스레드의 인스턴스 값으로 초기화 된 스레드 로컬 변수를 사용자 환경에 적용 할 수 있습니다. – Omnifarious