stringtranslate.com

Состояние гонки

Состояние гонки в логической схеме. Здесь t 1 и t 2 представляют собой задержки распространения логических элементов. Когда входное значение A меняется с низкого на высокое, схема выдает короткий всплеск продолжительностью (∆ t 1 + ∆ t 2 ) − ∆ t 2 = ∆ t 1 .

Состояние гонки или опасность гонки — это состояние электроники , программного обеспечения или другой системы , при котором существенное поведение системы зависит от последовательности или времени других неконтролируемых событий, что приводит к неожиданным или противоречивым результатам. Это становится ошибкой , когда одно или несколько возможных вариантов поведения нежелательны.

Термин « состояние гонки» уже использовался к 1954 году, например, в докторской диссертации Дэвида А. Хаффмана «Синтез схем последовательного переключения». [1]

Условия гонки могут возникнуть, особенно в логических схемах , многопоточных или распределенных программах.

В электронике

Типичный пример состояния гонки может возникнуть, когда логический элемент объединяет сигналы, прошедшие по разным путям от одного и того же источника. Входные сигналы вентиля могут меняться в несколько разное время в ответ на изменение исходного сигнала. Выходной сигнал может на короткое время перейти в нежелательное состояние, прежде чем вернуться в расчетное состояние. Некоторые системы могут терпеть такие сбои , но если этот выходной сигнал действует как тактовый сигнал , например, для других систем, содержащих память, система может быстро отклониться от запланированного поведения (по сути, временный сбой становится постоянным сбоем).

Рассмотрим, например, вентиль И с двумя входами , питаемый следующей логикой:

логическое отрицание[2]

Практический пример состояния гонки может возникнуть, когда логическая схема используется для обнаружения определенных выходных сигналов счетчика. Если все биты счетчика не изменяются точно одновременно, возникнут промежуточные шаблоны, которые могут вызвать ложные совпадения.

Критические и некритические формы

Критическое состояние гонки возникает, когда порядок изменения внутренних переменных определяет конечное состояние, в котором окажется конечный автомат .

Некритическое состояние гонки возникает, когда порядок изменения внутренних переменных не определяет конечное состояние, в котором окажется конечный автомат.

Статические, динамические и существенные формы

Состояние статической гонки возникает при объединении сигнала и его дополнения.

Состояние динамической гонки возникает, когда оно приводит к множеству переходов, хотя предназначен только один. Они возникают из-за взаимодействия между воротами. Его можно устранить, используя не более двух уровней стробирования.

Существенное состояние гонки возникает, когда входной сигнал имеет два перехода за время, меньшее общего времени распространения обратной связи. Иногда их устраняют с помощью индуктивных элементов линии задержки , чтобы эффективно увеличить длительность входного сигнала.

Обходные пути

Такие методы проектирования, как карты Карно, побуждают дизайнеров распознавать и устранять условия гонки до того, как они вызовут проблемы. Часто для устранения некоторых видов гонок можно добавить логическую избыточность .

Помимо этих проблем, некоторые логические элементы могут переходить в метастабильные состояния , что создает дополнительные проблемы для разработчиков схем.

В программном обеспечении

Состояние гонки может возникнуть в программном обеспечении, когда компьютерная программа имеет несколько путей кода, которые выполняются одновременно. Если несколько путей кода занимают другое количество времени, чем ожидалось, они могут завершиться в другом порядке, чем ожидалось, что может вызвать ошибки программного обеспечения из-за непредвиденного поведения. Между двумя программами также может возникнуть гонка, приводящая к проблемам с безопасностью (см. ниже).

Критические условия гонки приводят к некорректному выполнению и ошибкам программного обеспечения . Критические условия гонки часто возникают, когда процессы или потоки зависят от некоторого общего состояния. Операции над общими состояниями выполняются в критических секциях , которые должны быть взаимоисключающими . Несоблюдение этого правила может испортить общее состояние.

Гонка данных — это тип состояния гонки. Гонки данных являются важной частью различных формальных моделей памяти . Модель памяти, определенная в стандартах C11 и C++11, указывает, что программа C или C++, содержащая гонку данных, имеет неопределенное поведение . [3] [4]

Состояние гонки может быть сложно воспроизвести и отладить, поскольку конечный результат недетерминирован и зависит от относительного времени между мешающими потоками. Таким образом, проблемы такого рода могут исчезнуть при работе в режиме отладки, добавлении дополнительного журналирования или подключении отладчика. Ошибку, которая исчезает таким образом во время попыток отладки, часто называют « гейзенбагом ». Поэтому лучше избегать состояний гонки путем тщательной разработки программного обеспечения.

Пример

Предположим, что каждый из двух потоков увеличивает значение глобальной целочисленной переменной на 1. В идеале должна иметь место следующая последовательность операций:

В случае, показанном выше, конечное значение равно 2, как и ожидалось. Однако если два потока выполняются одновременно без блокировки или синхронизации (через семафоры ), результат операции может быть неправильным. Альтернативная последовательность операций ниже демонстрирует этот сценарий:

В этом случае окончательное значение равно 1 вместо ожидаемого результата 2. Это происходит потому, что здесь операции приращения не являются взаимоисключающими. Взаимоисключающие операции — это операции, которые нельзя прервать при доступе к какому-либо ресурсу, например к ячейке памяти.

Гонка данных

Не все рассматривают гонку данных как подмножество условий гонки. [5] Точное определение гонки данных зависит от используемой формальной модели параллелизма, но обычно оно относится к ситуации, когда операция с памятью в одном потоке потенциально может попытаться получить доступ к ячейке памяти одновременно с операцией с памятью в другой поток записывает данные в эту область памяти в контексте, где это опасно. Это означает, что гонка данных отличается от состояния гонки, поскольку недетерминированность из-за тайминга может быть даже в программе без гонок за данными, например, в программе, в которой все обращения к памяти используют только атомарные операции .

Это может быть опасно, поскольку на многих платформах, если два потока одновременно записывают данные в определенную ячейку памяти, эта ячейка памяти может в конечном итоге содержать значение, представляющее собой некую произвольную и бессмысленную комбинацию битов, представляющих значения, которые каждый поток пытался писать; это может привести к повреждению памяти, если полученное значение не будет записано ни одним потоком (иногда это называется «прерванной записью»). Аналогично, если один поток читает из определенного места, в то время как другой поток записывает в него, возможно, что чтение вернет значение, представляющее собой некую произвольную и бессмысленную комбинацию битов, представляющих значение, которое эта ячейка памяти хранила до записи. и битов, представляющих записываемое значение.

На многих платформах для одновременного доступа предусмотрены специальные операции с памятью; в таких случаях обычно одновременный доступ с использованием этих специальных операций безопасен, но одновременный доступ с использованием других операций с памятью опасен. Иногда такие специальные операции (безопасные для одновременного доступа) называются атомарными операциями или операциями синхронизации , тогда как обычные операции (небезопасные для одновременного доступа) называются операциями с данными . Вероятно, поэтому используется термин « гонка данных »; на многих платформах, где существует состояние гонки, включающее только операции синхронизации , такая гонка может быть недетерминированной, но в остальном безопасной; но гонка данных может привести к повреждению памяти или неопределенному поведению.

Примеры определений гонок данных в конкретных моделях параллелизма

Точное определение гонки данных различается в разных формальных моделях параллелизма. Это важно, поскольку параллельное поведение часто не интуитивно понятно и поэтому иногда применяются формальные рассуждения.

Стандарт C++ в проекте N4296 (19 ноября 2014 г.) определяет гонку данных следующим образом в разделе 1.10.23 (стр. 14) [6]

Два действия потенциально параллельны, если

Выполнение программы содержит гонку данных , если она содержит два потенциально одновременных конфликтующих действия, по крайней мере одно из которых не является атомарным, и ни одно из них не происходит раньше другого, за исключением особого случая для обработчиков сигналов, описанных ниже [опущено]. Любая такая гонка данных приводит к неопределенному поведению.

Части этого определения, относящиеся к обработчикам сигналов, характерны для C++ и не типичны для определений гонки данных .

В статье «Обнаружение гонок данных в слабых системах памяти» [7] дано другое определение:

«две операции с памятью конфликтуют, если они обращаются к одному и тому же месту и хотя бы одна из них является операцией записи... «Две операции с памятью, x и y, при последовательном последовательном выполнении образуют гонку 〈x,y〉, если и только если x и y конфликтуют, и они не упорядочиваются отношением выполнения hb1. Гонка 〈x,y〉 является гонкой данных тогда и только тогда, когда хотя бы одна из x или y является операцией с данными.

Здесь у нас есть две операции с памятью, обращающиеся к одному и тому же месту, одна из которых — запись.

Отношение hb1 определено в другом месте статьи и является примером типичного отношения « происходит до »; интуитивно, если мы можем доказать, что находимся в ситуации, когда одна операция с памятью X гарантированно будет выполнена до завершения до того, как начнется другая операция с памятью Y, тогда мы говорим, что «X происходит - до Y». Если ни «X не происходит до Y», ни «Y не происходит до X», то мы говорим, что X и Y «не упорядочены отношением hb1». Таким образом, предложение «...и они не упорядочены отношением выполнения hb1» можно интуитивно перевести как «...и X и Y потенциально параллельны».

В статье опасными считаются только те ситуации, в которых хотя бы одна из операций с памятью является «операцией с данными»; в других частях этой статьи также определяется класс «операций синхронизации», которые безопасны для потенциально одновременного использования, в отличие от «операций с данными».

Спецификация языка Java [8] дает другое определение:

Два доступа к одной и той же переменной (чтение или запись) считаются конфликтующими, если хотя бы один из них является записью... Когда программа содержит два конфликтующих доступа (§17.4.1), которые не упорядочены Говорят, что отношение происходит до того, как оно содержит гонку данных... гонка данных не может вызвать неправильное поведение, например возврат неправильной длины для массива.

Критическое различие между подходом C++ и подходом Java заключается в том, что в C++ гонка данных представляет собой неопределенное поведение, тогда как в Java гонка данных просто влияет на «действия между потоками». [8] Это означает, что в C++ попытка выполнить программу, содержащую гонку данных, может (при соблюдении спецификации) привести к сбою или может демонстрировать небезопасное или странное поведение, тогда как в Java попытка выполнить программу, содержащую данные, может привести к сбою или демонстрировать небезопасное или странное поведение. Race может привести к нежелательному поведению параллелизма, но в остальном (при условии, что реализация соответствует спецификации) безопасен.

Последовательная согласованность для свободы гонок за данными

Важным аспектом гонок данных является то, что в некоторых контекстах программа, свободная от гонок данных, гарантированно будет выполняться последовательно-согласованным образом, что значительно упрощает рассуждения о параллельном поведении программы. Говорят, что формальные модели памяти, обеспечивающие такую ​​гарантию, обладают свойством «SC for DRF» (последовательная согласованность для свободы гонок данных). Говорят, что этот подход недавно достиг консенсуса (предположительно по сравнению с подходами, которые гарантируют последовательную согласованность во всех случаях, или подходами, которые не гарантируют ее вообще). [9]

Например, в Java эта гарантия указана прямо: [8]

Программа правильно синхронизирована тогда и только тогда, когда все последовательно согласованные выполнения свободны от гонок данных.

Если программа правильно синхронизирована, то все ее выполнения будут выглядеть последовательно согласованными (§17.4.3).

Это чрезвычайно сильная гарантия для программистов. Программистам не нужно рассуждать о переупорядочении, чтобы определить, что их код содержит гонки данных. Поэтому им не нужно рассуждать о переупорядочении при определении правильности синхронизации их кода. Как только будет установлено, что код правильно синхронизирован, программисту не нужно беспокоиться о том, что переупорядочение повлияет на его или ее код.

Программа должна быть правильно синхронизирована, чтобы избежать нелогичного поведения, которое можно наблюдать при переупорядочении кода. Использование правильной синхронизации не гарантирует правильности общего поведения программы. Однако его использование позволяет программисту простым способом рассуждать о возможном поведении программы; поведение правильно синхронизированной программы гораздо меньше зависит от возможных переупорядочений. Без правильной синхронизации возможно очень странное, запутанное и нелогичное поведение.

Напротив, в проекте спецификации C++ прямо не требуется SC для свойства DRF, а просто отмечается, что существует теорема, обеспечивающая это свойство:

[Примечание: можно показать, что программы, которые правильно используют мьютексы и операции Memory_order_seq_cst для предотвращения всех гонок данных и не используют никаких других операций синхронизации, ведут себя так, как будто операции, выполняемые их составляющими потоками, просто чередуются, при этом каждое вычисление значения объекта выполняется от последнего побочного эффекта на этот объект в этом чередовании. Обычно это называется «последовательной согласованностью». Однако это применимо только к программам без гонок за данными, а программы без гонок за данными не могут наблюдать большинство преобразований программы, которые не меняют семантику однопоточной программы. Фактически, большинство однопоточных преобразований программ по-прежнему разрешены, поскольку любая программа, которая в результате ведет себя по-другому, должна выполнить неопределенную операцию.

Обратите внимание, что проект спецификации C++ допускает возможность использования программ, которые являются допустимыми, но используют операции синхронизации с Memory_order, отличным от Memory_order_seq_cst, и в этом случае результатом может быть программа, которая является правильной, но для которой не предоставляется гарантия последовательной согласованности. Другими словами, в C++ некоторые правильные программы не являются последовательно согласованными. Считается, что этот подход дает программистам C++ свободу выбирать более быстрое выполнение программы за счет отказа от простоты рассуждений о своей программе. [9]

Существуют различные теоремы, часто представленные в форме моделей памяти, которые обеспечивают гарантии SC для DRF в различных контекстах. Посылки этих теорем обычно налагают ограничения как на модель памяти (и, следовательно, на реализацию), так и на программиста; иными словами, обычно бывает так, что существуют программы, которые не соответствуют предпосылкам теоремы и не может быть гарантировано последовательное выполнение.

Модель памяти DRF1 [10] обеспечивает SC для DRF и позволяет оптимизировать WO (слабый порядок), RCsc ( согласованность выпуска с последовательно согласованными специальными операциями), модель памяти VAX и модели памяти без гонок данных 0. Модель памяти PLpc [11] обеспечивает SC для DRF и позволяет оптимизировать модели TSO (общий порядок хранения), PSO, PC ( согласованность процессора ) и RCpc ( согласованность выпуска со специальными операциями согласованности процессора). DRFrlx [12] представляет схему SC для теоремы DRF в присутствии релаксированных атомов.

Компьютерная безопасность

Многие условия гонки программного обеспечения имеют последствия для компьютерной безопасности . Состояние гонки позволяет злоумышленнику, имеющему доступ к общему ресурсу, вызывать сбои в работе других участников, использующих этот ресурс, что приводит к таким последствиям, как отказ в обслуживании [13] и повышение привилегий . [14] [15]

Конкретный вид состояния гонки включает в себя проверку предиката (например, для аутентификации ), затем действие на предикат, при этом состояние может меняться между временем проверки и временем использования . Когда ошибка такого типа существует в коде, чувствительном к безопасности, создается уязвимость безопасности , называемая ошибкой времени проверки до времени использования ( TOCTTOU ).

Условия гонки также намеренно используются для создания аппаратных генераторов случайных чисел и физически неклонируемых функций . [16] [ нужна цитация ] PUF могут быть созданы путем проектирования топологий схемы с идентичными путями к узлу и использования производственных изменений, чтобы случайным образом определить, какие пути завершатся первыми. Измеряя конкретный набор результатов состояния гонки для каждой изготовленной схемы, можно собрать профиль для каждой схемы и сохранить его в секрете, чтобы позже проверить идентичность схемы.

Файловые системы

Две или более программы могут столкнуться при попытке изменить файловую систему или получить к ней доступ, что может привести к повреждению данных или повышению привилегий. [14] Блокировка файлов является широко используемым решением. Более громоздкое решение предполагает организацию системы таким образом, чтобы один уникальный процесс (запускающий демон и т.п.) имел монопольный доступ к файлу, а все остальные процессы, которым необходим доступ к данным в этом файле, делали это только посредством межпроцессного взаимодействия. с этим одним процессом. Для этого требуется синхронизация на уровне процесса.

Другая форма состояния гонки существует в файловых системах, где несвязанные программы могут влиять друг на друга, внезапно используя доступные ресурсы, такие как дисковое пространство, пространство памяти или циклы процессора. Программное обеспечение, не разработанное должным образом для предвидения и управления этой гоночной ситуацией, может стать непредсказуемым. Такой риск может долгое время игнорироваться в системе, которая кажется очень надежной. Но в конечном итоге может накопиться достаточно данных или может быть добавлено достаточно другого программного обеспечения, чтобы критически дестабилизировать многие части системы. Примером этого стала гибель марсохода «Спирит» вскоре после приземления. Решение состоит в том, чтобы программное обеспечение запрашивало и резервировало все необходимые ему ресурсы перед началом задачи; если этот запрос завершается неудачно, задача откладывается, что позволяет избежать многих моментов, когда мог произойти сбой. В качестве альтернативы, каждая из этих точек может быть оснащена обработкой ошибок, или успех всей задачи может быть проверен впоследствии, прежде чем продолжить. Более распространенный подход — просто проверить наличие достаточного количества системных ресурсов перед запуском задачи; однако этого может быть недостаточно, поскольку в сложных системах действия других работающих программ могут быть непредсказуемыми.

сеть

В сети рассмотрим распределенную чат-сеть, такую ​​как IRC , где пользователь, запускающий канал, автоматически получает привилегии оператора канала. Если два пользователя на разных серверах, на разных концах одной сети, попытаются одновременно запустить один и тот же канал, соответствующий сервер каждого пользователя предоставит привилегии оператора канала каждому пользователю, поскольку ни один из серверов еще не получил сигнал другого сервера о том, что он выделил этот канал. (Эта проблема в значительной степени решена различными реализациями IRC-сервера.)

В этом случае состояния гонки понятие « общий ресурс » охватывает состояние сети (какие каналы существуют, а также какие пользователи их запустили и, следовательно, имеют какие привилегии), которое каждый сервер может свободно изменять до тех пор, пока он сигнализирует другим серверам в сети об изменениях, чтобы они могли обновить свое представление о состоянии сети. Однако задержка в сети делает возможным описанный тип гонки. В этом случае предотвращение условий гонки путем введения формы контроля над доступом к общему ресурсу — скажем, назначение одного сервера для контроля того, кто обладает какими привилегиями — будет означать превращение распределенной сети в централизованную (по крайней мере, для этой части). работы сети).

Условия гонки также могут существовать, когда компьютерная программа написана с использованием неблокирующих сокетов , и в этом случае производительность программы может зависеть от скорости сетевого соединения.

Жизненно важные системы

Ошибки программного обеспечения в жизненно важных системах могут иметь катастрофические последствия. Условия гонки были среди недостатков аппарата лучевой терапии Therac-25 , что привело к гибели как минимум трех пациентов и ранениям еще нескольких. [17]

Другим примером является система управления энергопотреблением , предоставленная GE Energy и используемая базирующейся в Огайо компанией FirstEnergy Corp (среди других энергетических предприятий). В подсистеме сигнализации существовало состояние гонки; Когда одновременно были отключены три провисающие линии электропередачи, из-за этого условия специалисты по мониторингу не были предупреждены, что задержало их осведомленность о проблеме. Этот программный недостаток в конечном итоге привел к отключению электроэнергии в Северной Америке в 2003 году . [18] Позднее GE Energy разработала исправление программного обеспечения для исправления ранее не обнаруженной ошибки.

Инструменты

Существует множество программных инструментов, помогающих обнаруживать состояния гонки в программном обеспечении. Их можно разделить на две группы: инструменты статического анализа и инструменты динамического анализа .

Анализ безопасности потоков — это инструмент статического анализа для внутрипроцедурного статического анализа на основе аннотаций, первоначально реализованный как ветвь gcc, а теперь перереализованный в Clang с поддержкой PThreads. [19] [ нужен неосновной источник ]

Инструменты динамического анализа включают в себя:

Существует несколько тестов, предназначенных для оценки эффективности инструментов обнаружения гонок за данными.

В других областях

Нейронауки показывают, что расовые состояния могут возникать и в мозге млекопитающих. [24] [25]

В системе железнодорожной сигнализации Великобритании при выполнении Правила 55 может возникнуть состояние гонки . Согласно этому правилу, если поезд был остановлен на ходу сигналом, пожарный локомотива подходил к сигнальной будке, чтобы напомнить сигнальщику о присутствии поезда. По крайней мере, в одном случае, в Уинвике в 1934 году, произошла авария из-за того, что сигнальщик принял другой поезд до прибытия пожарного. Современная практика сигнализации устраняет состояние гонки, позволяя водителю мгновенно связаться с сигнальной будкой по радио.

Смотрите также

Рекомендации

  1. ^ Хаффман, Дэвид А. «Синтез схем последовательного переключения». (1954).
  2. ^ Унгер, SH (июнь 1995 г.). «Опасности, критические гонки и метастабильность». Транзакции IEEE на компьютерах . 44 (6): 754–768. дои : 10.1109/12.391185.
  3. ^ «ISO/IEC 9899:2011 – Информационные технологии – Языки программирования – C» . Исо.орг . Проверено 30 января 2018 г.
  4. ^ «ISO/IEC 14882:2011». ИСО. 2 сентября 2011 года . Проверено 3 сентября 2011 г.
  5. ^ Регер, Джон (13 марта 2011 г.). «Состояние гонки против гонки данных». Встроен в академию .
  6. ^ «Рабочий проект стандарта языка программирования C++» (PDF) . 19 ноября 2014 г.
  7. ^ Адве, Сарита и Хилл, Марк и Миллер, Бартон и Х. Б. Нетцер, Роберт. (1991). Обнаружение гонок за данными в системах со слабой памятью. Новости компьютерной архитектуры ACM SIGARCH. 19. 234–243. 10.1109/ISCA.1991.1021616.
  8. ^ abc «Глава 17. Нити и замки». docs.oracle.com .
  9. ^ аб Адве, Сарита В.; Бём, Ханс-Й. (2010). «Семантика общих переменных и синхронизация (также известные как модели памяти)» (PDF) .
  10. ^ Адве, Сарита (декабрь 1993 г.). Разработка моделей согласованности памяти для мультипроцессоров с общей памятью (PDF) (кандидатская диссертация). Архивировано (PDF) из оригинала 9 декабря 2021 г. Проверено 9 декабря 2021 г.
  11. ^ Курош Гарачорлоо, Сарита В. Адве и Ануп Гупта, Джон Л. Хеннесси и Марк Д. Хилл, Программирование для различных моделей согласованности памяти, Журнал параллельных и распределенных вычислений, 1992, том 15, страницы 399–407.
  12. ^ Синклер, Мэтью Дэвид (2017). «Глава 3: Эффективная поддержка и оценка релаксированной атомики» (PDF) . Эффективная когерентность и согласованность для специализированных иерархий памяти (доктор философии). Университет Иллинойса в Урбане-Шампейне.
  13. ^ «CVE-2015-8461: Состояние гонки при обработке ошибок сокета может привести к сбою утверждения в resolver.c». Консорциум Интернет-систем . Проверено 5 июня 2017 г.
  14. ^ ab «Уязвимость в rmtree() и remove_tree(): CVE-2017-6512». КПАН . Проверено 5 июня 2017 г.
  15. ^ «Безопасность: кэш статистики *очень большой*, состояние гонки, если кеширование отключено, когда Follow_symlink отключен». светтпд . Проверено 5 июня 2017 г.
  16. ^ Колеса, Адриан; Тудоран, Раду; Банеску, Себастьян (2008). «Программное обеспечение генерации случайных чисел на основе условий гонки». 2008 10-й Международный симпозиум по символьным и числовым алгоритмам для научных вычислений . стр. 439–444. дои : 10.1109/synasc.2008.36. ISBN 978-0-7695-3523-4. S2CID  1586029.
  17. ^ Левесон, Нэнси; Тернер, Кларк С. «Расследование несчастных случаев на Therac-25 - I». Курсы.cs.vt.edu. Архивировано из оригинала 15 декабря 2017 г.
  18. ^ Поулсен, Кевин (7 апреля 2004 г.). «Отслеживание ошибки отключения электроэнергии». БезопасностьФокус . Проверено 19 сентября 2011 г.
  19. ^ «Анализ безопасности потоков - документация Clang 10» . clang.llvm.org .
  20. ^ «ThreadSanitizer - документация Clang 10» . clang.llvm.org .
  21. ^ «Helgrind: детектор ошибок потока» . Валгринд .
  22. ^ «Детектор гонки данных» . Голанг .
  23. ^ «Набор тестов гонок данных» . 25 июля 2019 г. — через GitHub.
  24. ^ «Как мозг гонится за отменой ошибочных движений» . Нейроскептик . Откройте для себя журнал. 03.08.2013. Архивировано из оригинала 6 августа 2013 г. Проверено 7 августа 2013 г.
  25. ^ Шмидт, Роберт; Левенталь, Дэниел К; Маллет, Николас; Чен, Фуцзюнь; Берке, Джошуа Д. (2013). «Отмена действий предполагает гонку между путями базальных ганглиев». Природная неврология . 16 (8): 1118–24. дои : 10.1038/nn.3456. ПМЦ 3733500 . ПМИД  23852117. 

Внешние ссылки