2012-10-14 5 views
6

나는 비동기식으로 응용 프로그램 (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 참조).

답변

0

상황을 업데이트하기위한 인터페이스를 제공하는 이러한 작업에 일종의 컨텍스트 개체를 전달할 수없는 이유가 있습니까? 왜냐하면 내가 서있는 곳에서, 당신은 싱글 톤 (일명 글로벌 변수)에 대한 나쁜 문제가있는 것으로 들린다. 하나는 의존성 주입으로 해결되어야한다.

종속성 삽입이 옵션이 아닌 경우에는 Singletons를 처리하기위한 또 다른 전략이 있습니다. 이 전략은 기본적으로 싱글 톤을 '스택'으로 허용합니다. Singleton에 새로운 값을 'push'할 수 있습니다. 그러면 액세스하는 모든 사람들이이 새로운 값을 얻습니다. 그런 다음 값을 다시 팝핑 할 수 있으며 푸시하기 전의 값이 복원됩니다. 이것은 실제 스택으로 직접 모델링 될 필요가 없기 때문에 'push', 'pop'및 'stack'을 따옴표로 묶어야합니다.

이 변수의 상위 스레드 버전의 값 (전체 값 스택이 아니라 최상위 값)으로 초기화되는 스레드 로컬 싱글 톤을 사용하면 상황에 맞게이 모델을 적용 할 수 있습니다. 그런 다음이 스레드와 그 자식에 대해 새 컨텍스트가 필요한 경우 새 값을 스레드 로컬 Singleton에 푸시 (push) 할 수 있습니다.

+0

그렇습니다. 명백한 해결책이며, 이는 기본적으로 대부분의 코드에서 수행합니다. 그러나 코드의 하위 집합에 대해서는 과도한 상세 표시로 이어질 수 있으므로 옵션이 아닙니다. 기본적으로 setters/getters가있는 코드 생성 데이터 객체 클래스가 있습니다. 게터는 데이터 의존성을 추적하기 위해 사용 된 것을 등록하도록 선택적으로 계측 할 수 있습니다. 컨텍스트 객체를이 모든 getter에 전달하고 컨텍스트를 모든 호출 체인에서 처리해야하는 것은 매우 어색합니다. 기본적으로 스케줄러 ID를 사용하여 스케줄러 로컬 변수를 구현하면 좋은 성능으로 작동합니다. –

+0

@StefanBoberg : 싱글 톤이 아닌 싱글 톤을위한 대체 모델이 있습니다. 그것은 당신이 값을 '쌓아 올리는'것을 허락합니다. 새 값을 스택에 푸시 (push) 할 수 있으며 값이 팝되고 이전 값이 복원 될 때까지는 싱글 톤 값이됩니다. 이 변수의 부모 스레드의 인스턴스 값으로 초기화 된 스레드 로컬 변수를 사용자 환경에 적용 할 수 있습니다. – Omnifarious