2012-10-14 12 views
6

Poprawiam aplikację (Win64, C++), czyniąc ją bardziej asynchroniczną. Używam środowiska wykonawczego Concurrency Runtime i jak na razie świetnie się sprawdziło.Implementowanie zmiennych lokalnych zadania dla aplikacji wykonawczej współbieżności

Aplikacja zasadniczo wykonuje szereg danych transformujących zadania. Aby śledzić, co robi każda praca, niektóre podsystemy są wyposażone w kod do śledzenia określonych operacji wykonywanych przez zadanie. Poprzednio korzystałaby z pojedynczej zmiennej globalnej reprezentującej aktualnie wykonywaną pracę, aby móc rejestrować informacje o śledzeniu bez konieczności przekazywania informacji kontekstowych do końca łańcucha wywołującego. Każde zlecenie może również wykorzystywać ConcRT do równoległego samego zadania. Wszystko działa całkiem dobrze.

Teraz jednak dokonuję refaktoryzacji aplikacji, aby umożliwić równoległe wykonywanie zadań najwyższego poziomu. Każde zadanie jest wykonywane jako zadanie ConcRT, a to działa dobrze dla wszystkich zadań oprócz tych, które wymagają śledzenia.

To, czego potrzebuję, to sposób na powiązanie niektórych informacji kontekstowych z zadaniem i przekazanie tego przepływu do innych zadań tworzonych przez to zadanie. Zasadniczo potrzebuję zmiennych "Task Local".

W ConcRT nie możemy po prostu użyć lokali wątku do przechowywania informacji kontekstowych, ponieważ zadanie może spawnować inne zadania za pomocą ConcRT, a te będą wykonywane na dowolnej liczbie wątków.

Moje obecne podejście polega na tworzeniu wielu instancji programu planującego przy uruchamianiu i tworzeniu poszczególnych zadań w harmonogramie poświęconym temu zadaniu. Mogę następnie użyć funkcji Concurrency::CurrentScheduler::Id(), aby pobrać identyfikator liczb całkowitych, który mogę wykorzystać jako klucz do określenia kontekstu. To działa, ale pojedynczy krok przez Concurrency::CurrentScheduler::Id() w zestawie sprawia, że ​​trochę się skrzywięszę, ponieważ wykonuje wiele wirtualnych wywołań funkcji i kontroli bezpieczeństwa, co dodaje sporo narzutów, co jest problemem, ponieważ to wyszukiwanie musi być wykonane w wysoka stopa w niektórych przypadkach.

Czy jest jakiś lepszy sposób, aby to osiągnąć? Byłbym bardzo zadowolony z posiadania pierwszorzędnego mechanizmu TaskLocal/userdata, który pozwolił mi powiązać pojedynczy wskaźnik kontekstowy z bieżącym harmonogramem/harmonogramem zadań/zadaniem, który mógłbym pobrać z bardzo niewielkim narzutem.

Haczyk, który jest wywoływany za każdym razem, gdy wątek ConcRT chwyta nowe zadanie, byłby moim idealnym rozwiązaniem, ponieważ mógłbym pobrać identyfikator Scheduler/ScheduleGroup ID i zapisać go w wątku lokalnym, aby uzyskać minimalny dostęp z góry. Niestety, nie widzę żadnego sposobu na zarejestrowanie takiego haka i wydaje się, że nie jest możliwe zaimplementowanie niestandardowych klas Scheduler dla PPL/agentów (patrz this article).

Odpowiedz

0

Czy jest jakiś powód, dla którego nie można przekazać jakiegoś kontekstowego obiektu do tych zadań, który zapewnia interfejs do aktualizacji ich statusu? Ponieważ z miejsca, w którym stoję, wygląda na to, że masz naprawdę zły problem z Singletonami (inaczej zmiennymi globalnymi), który należy rozwiązać za pomocą zastrzyku zależności.

Jeśli wstrzyknięcie zależności nie jest możliwe, istnieje inna strategia postępowania z Singletonami. Ta strategia zasadniczo pozwala Singletonowi być "stosem". Możesz "wypchnąć" nową wartość do Singleton, a wtedy wszyscy, którzy uzyskują do niej dostęp, otrzymają tę nową wartość. A następnie możesz "wyrzucić" wartość z powrotem, a wartość przed pchnięciem zostanie przywrócona. Nie musi to być bezpośrednio modelowane za pomocą rzeczywistego stosu, dlatego umieszczam słowa "push", "pop" i "stack" w cudzysłowach.

Możesz dostosować ten model do swojej sytuacji, używając wątku lokalnego Singleton, który jest zainicjalizowany wartością (nie całym stosem wartości, tylko najwyższą wartością) wersji tej zmiennej dla wątku nadrzędnego. Następnie, jeśli wymagany jest nowy kontekst dla tego wątku i jego elementów potomnych, można wprowadzić nową wartość do lokalnego Singleton.

+0

Tak, to oczywiste rozwiązanie, i to w zasadzie to, co robimy dla większości naszego kodu. Jednak dla podzbioru kodu nie jest to opcja, ponieważ prowadziłaby do nadmiernej szczegółowości. Zasadniczo mamy klasy obiektów danych generowanych przez kod z setter/getters. Opcjonalnie moduły Getters mogą zostać zarejestrowane w celu zarejestrowania, że ​​zostały użyte, w celu śledzenia zależności danych. Byłoby bardzo niezręcznie, gdybyśmy przekazywali obiekty kontekstowe do wszystkich tych elementów pobierających i rozwijali kontekst w dół wszystkich łańcuchów wywołań. Korzystanie z Identyfikatora harmonogramu do podstawowego wdrożenia zmiennych lokalnych programu planującego działa jednak z dobrą wydajnością. –

+0

@StefanBoberg: Istnieje alternatywny model Singleton, który nie jest tak naprawdę Singletonem. Pozwala na "stackowanie" wartości. Możesz dodać nową wartość do stosu, która staje się wartością Singletona, dopóki wartość nie zniknie, a stara wartość zostanie przywrócona. Możesz dostosować to do swojego środowiska, używając zmiennej lokalnej wątku zainicjowanej wartością instancji wątku nadrzędnego tej zmiennej. – Omnifarious

Powiązane problemy