Pytanie W jaki sposób MRI analizuje operatory `|| =`?


Dzisiaj próbowałem wyjaśnić to współpracownikowi ||= nie jest wątkowo bezpieczny w MRI. Pomyślałem, że przyjrzę się źródłu Ruby i spróbuję sprawdzić, czy mogę wskazać miejsce, w którym program planujący Ruby może zmienić kontekst wątku, ale mam problem z nawigacją po kodzie. Miałem nadzieję, że ktoś bardziej doświadczony może przejść przez pliki, które zostały trafione.

Do tej pory wiem, że Bison bierze parse.y i generuje parse.c plik, który wywołuje niektóre podstawowe funkcje. Widzę to || jest parsowany jako tOROP ale potem tracę trochę na tym, co dzieje się dalej

Czy jest jakieś narzędzie, takie jak Ripper, którego mogę użyć, aby ułatwić ten proces? (I w tym przypadku byłoby pomocne, gdyby ktoś mógł wskazać mi, gdzie jest zdefiniowany kod źródłowy Rippera)


14
2017-09-10 17:16


pochodzenie


Tak jak x += 1 jest nieatomowy. Wymaga odczytu, porównania i (warunkowego) przypisania. x ||= y jest skutecznie x = x || y lub x = y unless (x) w zależności od tego, jak konkretnie chcesz się dostać. Zwróć uwagę w obu przypadkach na przeczytanie i porównanie (nie fałszywy) jest wymagane przed przydzieleniem. Wszystko może się zdarzyć w tej luce. Możesz przyjrzeć się temu, co MRI kodu bajtowego wyraża to stwierdzenie, aby wiedzieć, co dzieje się wewnętrznie. - tadman
MRI ruby ma --dump opcja. Myślę, że szukasz --dump yydebug ale możesz być także zainteresowany parsetree lub insns. - cremno
@cremno Bardzo miło! To zdecydowanie duża pomoc ruby -e "@hello ||= 'hi'" --dump parsetree wydaje się, że powinien być bardzo użyteczny - Josh Bodah
Myślę, że to moc być "przypadkowo" bezpieczny dla wątków w MRI (ale nie JRuby). Rozumiem, o co pytasz, i nie wiem, gdzie jest kod C, aby wskazać ci to, ale widziałem artykuły na ten temat, zanim może znajdziesz google. W MRI masz rację, że GIL jest uwalniany tylko w pewnych punktach i jest to możliwe ||= może przypadkowo zakończyć wątek, ale nawet jeśli jest to jego szczegół implementacji, może ulec zmianie i nie jest bezpieczny dla innych tłumaczy. - jrochkind
Bezpieczeństwo wątków nie ma nic wspólnego z analizatorem składni. Przestań tam patrzeć. Znak || = jest zapisywany jako sekwencja operacji (zobacz kod zespołu) i ta sekwencja może zostać przerwana, podczas której inny wątek może zmienić wartość, która została odczytana dla warunku. - cliffordheath


Odpowiedzi:


Zapomnienie parsera, jeśli spojrzysz na kod w compile.c tutaj zobaczysz, jak generowane są instrukcje do obsługi zadania lub operacji. Każde wywołanie ADD_INSNL powoduje wysłanie instrukcji. W linii 4553 widzisz gdyby warunek, który testuje wartość LHS po jej odczytaniu za pomocą kodu emitowanego przez wywołanie makra KOMPILACJA w linii 4546, w celu podjęcia decyzji, czy przypisać nową wartość. W tym czasie inny wątek może nadpisywać i zmieniać wartość, która została odczytana, więc przydział jest wykonywany (lub nie jest wykonywany), kiedy nie powinien być.

Jeśli chodzi o sposób tworzenia NODE_OP_ASGN_OR, zobacz wywołanie NEW_OP_ASGN_OR (zdefiniowane w node.h) wywoływane z parse.y w funkcji new_op_assign_gen ().

Mam nadzieję, że numery linii nie zmienią się zbyt wcześnie i unieważnią te adresy URL.


1
2017-11-04 08:05