Получите и отпустите примитивы синхронизации в том же модуле, на том же уровне абстракции
Получите и отпустите примитивы синхронизации в том же модуле, на том же уровне абстракции.[1]
Эта проверка проверяет на наличие следующих проблем:
Отсутствующий замок.
Отсутствует разблокировка.
Двойной замок.
Двойная разблокировка.
Отсутствующая блокировка возникает, когда задача вызывает функцию разблокировки перед вызовом соответствующей функции блокировки.
В многозадачном коде функция блокировки начинает критический раздел кода и функция разблокировки прекращает его. Когда задача my_task
вызывает функцию блокировки my_lock
, другие задачи, вызывающие my_lock
необходимо подождать до my_task
вызывает соответствующую функцию разблокировки. Polyspace® требует, чтобы функции блокировки и разблокировки имели форму void func(void)
.
Чтобы найти этот дефект, перед анализом необходимо задать опции многозадачности. Чтобы задать эти опции, на панели Configuration выберите Multitasking.
Вызов функции разблокировки без соответствующей функции блокировки может указывать на ошибку кодирования. Например, возможно, функция разблокировки не соответствует функции блокировки, которая начинает критический раздел.
Исправление зависит от первопричины дефекта. Например, если дефект возникает из-за несоответствия между функцией блокировки и разблокировки, проверьте пару функций блокировки и разблокировки в строении анализа Polyspace и исправьте несоответствие.
См. примеры исправлений ниже. Чтобы избежать проблемы, можно следовать практике вызова функций блокировки и разблокировки в том же модуле на том же уровне абстракции. Например, в этом примере func
вызывает функцию блокировки и разблокировки на том же уровне, но func2
не делает.
void func() { my_lock(); { // ... } my_unlock(); } void func2() { { my_lock(); // ... } my_unlock(); }
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset(void)
{
begin_critical_section();
global_var = 0;
end_critical_section();
}
void my_task(void)
{
global_var += 1;
end_critical_section();
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, вы должны задать следующие опции:
Опция | Спецификация | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points my_task,reset -critical-section-begin begin_critical_section:cs1 -critical-section-end end_critical_section:cs1
Пример имеет две точки входа, my_task
и reset
. my_task
вызывает end_critical_section
перед вызовом begin_critical_section
.
Одной из возможных коррекций является вызов функции блокировки begin_critical_section
перед инструкциями в критическом разделе.
void begin_critical_section(void); void end_critical_section(void); int global_var; void reset(void) { begin_critical_section(); global_var = 0; end_critical_section(); } void my_task(void) { begin_critical_section(); global_var += 1; end_critical_section(); }
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset() {
begin_critical_section();
global_var=0;
end_critical_section();
}
void my_task(void) {
int index=0;
volatile int numCycles;
while(numCycles) {
if(index%10==0) {
begin_critical_section();
global_var ++;
}
end_critical_section();
index++;
}
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, вы должны задать следующие опции:
Опция | Спецификация | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points my_task,reset -critical-section-begin begin_critical_section:cs1 -critical-section-end end_critical_section:cs1
Пример имеет две точки входа, my_task
и reset
.
В while
цикл, my_task
оставляет критический раздел через вызов end_critical_section();
. В итерации while
цикл:
Если my_task
входит в if
ветвь условия, критический раздел начинается через вызов begin_critical_section
.
Если my_task
не вводит if
условие ветви и покидает while
цикл, критический раздел не начинается. Поэтому возникает Missing lock дефект.
Если my_task
не вводит if
ветвь условия и продолжается до следующей итерации while
цикл, функция разблокировки end_critical_section
вызывается снова. Возникает Double unlock дефект.
Потому что numCycles
является volatile
переменная, она может взять любое значение. Возможен любой из вышеуказанных случаев. Поэтому на вызове появляются дефект Missing lock и дефект Double unlock end_critical_section
.
Отсутствующая разблокировка происходит, когда:
Задача вызывает функцию блокировки.
Задача заканчивается без вызова функции разблокировки.
В многозадачном коде функция блокировки начинает критический раздел кода и функция разблокировки прекращает его. Когда задача, my_task
, вызывает функцию блокировки, my_lock
, другие задачи, вызывающие my_lock
необходимо подождать до my_task
вызывает соответствующую функцию разблокировки. Polyspace требует, чтобы функции блокировки и разблокировки имели вид void func(void)
.
Чтобы найти этот дефект, перед анализом необходимо задать опции многозадачности. На панели Configuration выберите Multitasking.
Функция разблокировки заканчивает критический раздел, так что другие ожидающие задачи могут войти в критический раздел. Отсутствующая функция разблокировки может привести к блокировке задач на ненужное время.
Идентифицируйте критический раздел кода, то есть раздел, который вы хотите выполнить как атомарный блок. В конце этого раздела вызовите функцию разблокировки, которая соответствует функции блокировки, используемой в начале секции.
Могут быть другие причины и соответствующие исправления дефекта. Возможно, вы вызвали неправильную функцию разблокировки. Проверьте пару функций блокировки-разблокировки в строение анализа Polyspace и исправьте несоответствие.
См. примеры исправлений ниже. Чтобы избежать проблемы, можно следовать практике вызова функций блокировки и разблокировки в том же модуле на том же уровне абстракции. Например, в этом примере func
вызывает функцию блокировки и разблокировки на том же уровне, но func2
не делает.
void func() { my_lock(); { // ... } my_unlock(); } void func2() { { my_lock(); // ... } my_unlock(); }
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset()
{
begin_critical_section();
global_var = 0;
end_critical_section();
}
void my_task(void)
{
begin_critical_section();
global_var += 1;
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, задайте следующие опции:
Опция | Спецификация | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points my_task,reset -critical-section-begin begin_critical_section:cs1 -critical-section-end end_critical_section:cs1
Пример имеет две точки входа, my_task
и reset
. my_task
входит в критический раздел через вызов begin_critical_section();
. my_task
заканчивается без вызова end_critical_section
.
Одной из возможных коррекций является вызов функции разблокировки end_critical_section
после инструкций в критическом разделе.
void begin_critical_section(void); void end_critical_section(void); int global_var; void reset(void) { begin_critical_section(); global_var = 0; end_critical_section(); } void my_task(void) { begin_critical_section(); global_var += 1; end_critical_section(); }
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset() {
begin_critical_section();
global_var=0;
end_critical_section();
}
void my_task(void) {
int index=0;
volatile int numCycles;
while(numCycles) {
begin_critical_section();
global_var ++;
if(index%10==0) {
global_var = 0;
end_critical_section();
}
index++;
}
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, задайте следующие опции.
Опция | Спецификация | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points my_task,reset -critical-section-begin begin_critical_section:cs1 -critical-section-end end_critical_section:cs1
Пример имеет две точки входа, my_task
и reset
.
В while
цикл, my_task
входит в критический раздел через вызов begin_critical_section();
. В итерации while
цикл:
Если my_task
входит в if
ветвь условия, критический раздел заканчивается вызовом на end_critical_section
.
Если my_task
не вводит if
условие ветви и покидает while
цикл, критическое сечение не заканчивается. Поэтому возникает Missing unlock дефект.
Если my_task
не вводит if
ветвь условия и продолжается до следующей итерации while
цикл, функция блокировки begin_critical_section
вызывается снова. Возникает Double lock дефект.
Потому что numCycles
является volatile
переменная, она может взять любое значение. Любой из вышеуказанных случаев возможен. Поэтому на вызове появляются дефект Missing unlock и дефект Double lock begin_critical_section
.
Одной из возможных коррекций является вызов функции разблокировки end_critical_section
вне if
состояние.
void begin_critical_section(void); void end_critical_section(void); int global_var; void reset() { begin_critical_section(); global_var=0; end_critical_section(); } void my_task(void) { int index=0; volatile int numCycles; while(numCycles) { begin_critical_section(); global_var ++; if(index%10==0) { global_var=0; } end_critical_section(); index++; } }
Другой возможной коррекцией является вызов функции разблокировки end_critical_section
в каждой ветви if
состояние.
void begin_critical_section(void); void end_critical_section(void); int global_var; void reset() { begin_critical_section(); global_var=0; end_critical_section(); } void my_task(void) { int index=0; volatile int numCycles; while(numCycles) { begin_critical_section(); global_var ++; if(index%10==0) { global_var=0; end_critical_section(); } else end_critical_section(); index++; } }
Двойная блокировка происходит, когда:
Задача вызывает функцию блокировки my_lock
.
Задача вызывает my_lock
снова перед вызовом соответствующей функции разблокировки.
В многозадачном коде функция блокировки начинает критический раздел кода и функция разблокировки прекращает его. Когда задача task1
вызывает функцию блокировки lock
, другие задачи, вызывающие lock
необходимо подождать до task
вызывает соответствующую функцию разблокировки. Polyspace требует, чтобы функции блокировки и разблокировки имели вид void func(void)
.
Чтобы найти этот дефект, перед анализом необходимо задать опции многозадачности. Чтобы задать эти опции, на панели Configuration выберите Multitasking.
Вызов функции блокировки начинает критический раздел, так что другие задачи должны ждать, чтобы войти в тот же критический раздел. Если та же функция блокировки вызывается снова в критическом разделе, задача блокируется сама.
Исправление зависит от первопричины дефекта. Дефект двойной блокировки часто указывает на ошибку кодирования. Возможно, вы пропустили вызов функции разблокировки, чтобы закончить предыдущий критический раздел и начали следующий критический раздел. Возможно, вы хотели использовать другую функцию блокировки для второго критического раздела.
Идентифицируйте каждый критический раздел кода, то есть раздел, который вы хотите выполнить как атомарный блок. Вызовите функцию блокировки в начале раздела. В критическом разделе убедитесь, что вы не вызываете функцию блокировки снова. В конце раздела вызовите функцию разблокировки, которая соответствует функции блокировки.
См. примеры исправлений ниже. Чтобы избежать проблемы, можно следовать практике вызова функций блокировки и разблокировки в том же модуле на том же уровне абстракции. Например, в этом примере func
вызывает функцию блокировки и разблокировки на том же уровне, но func2
не делает.
void func() { my_lock(); { // ... } my_unlock(); } void func2() { { my_lock(); // ... } my_unlock(); }
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
int global_var;
void lock(void);
void unlock(void);
void task1(void)
{
lock();
global_var += 1;
lock();
global_var += 1;
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, вы должны задать следующие опции:
Опция | Спецификация | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
lock | unlock |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points task1,task2 -critical-section-begin lock:cs1 -critical-section-end unlock:cs1
task1
входит в критический раздел через вызов lock();
. task1
вызывает lock
снова, прежде чем он покинет критический раздел через вызов unlock();
.
Если вам нужен первый global_var+=1;
чтобы находиться вне критической секции, одной из возможных коррекций является удаление первого вызова на lock
. Однако, если используются другие задачи global_var
, этот код может создать Data race
ошибка.
int global_var; void lock(void); void unlock(void); void task1(void) { global_var += 1; lock(); global_var += 1; unlock(); } void task2(void) { lock(); global_var += 1; unlock(); }
Если вам нужен первый global_var+=1;
чтобы находиться внутри критической секции, одной из возможных коррекций является удаление второго вызова для lock
.
int global_var; void lock(void); void unlock(void); void task1(void) { lock(); global_var += 1; global_var += 1; unlock(); } void task2(void) { lock(); global_var += 1; unlock(); }
Если вам нужен второй global_var+=1;
чтобы находиться внутри критического раздела, другой возможной коррекцией является добавление другого вызова к unlock
.
int global_var; void lock(void); void unlock(void); void task1(void) { lock(); global_var += 1; unlock(); lock(); global_var += 1; unlock(); } void task2(void) { lock(); global_var += 1; unlock(); }
int global_var;
void lock(void);
void unlock(void);
void performOperation(void) {
lock();
global_var++;
}
void task1(void)
{
lock();
global_var += 1;
performOperation();
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, вы должны задать следующие опции:
Опция | Спецификация | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
lock | unlock |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points task1,task2 -critical-section-begin lock:cs1 -critical-section-end unlock:cs1
task1
входит в критический раздел через вызов lock();
. task1
вызывает функцию performOperation
. В performOperation
, lock
вызывается снова, хотя task1
не покинул критический раздел через вызов unlock();
.
В деталях результатов для дефекта вы видите последовательность инструкций, ведущих к дефекту. Например, вы видите, что после первого входа в критический раздел, путь выполнения:
Вводит функцию performOperation
.
Внутренние performOperation
, пытается войти в тот же критический раздел еще раз.
Можно кликнуть каждое событие, чтобы перейти к соответствующей линии в исходном коде.
Одной из возможных коррекций является удаление вызова на lock
в task1
.
int global_var; void lock(void); void unlock(void); void performOperation(void) { global_var++; } void task1(void) { lock(); global_var += 1; performOperation(); unlock(); } void task2(void) { lock(); global_var += 1; unlock(); }
Двойная разблокировка происходит, когда:
Задача вызывает функцию блокировки my_lock
.
Задача вызывает соответствующую функцию разблокировки my_unlock
.
Задача вызывает my_unlock
снова. Задача не вызывает my_lock
второй раз между двумя вызовами, чтобы my_unlock
.
В многозадачном коде функция блокировки начинает критический раздел кода и функция разблокировки прекращает его. Когда задача task1
вызывает функцию блокировки my_lock
, другие задачи, вызывающие my_lock
необходимо подождать до task1
вызывает соответствующую функцию разблокировки. Polyspace требует, чтобы функции блокировки и разблокировки имели вид void func(void)
.
Чтобы найти этот дефект, перед анализом необходимо задать опции многозадачности. Чтобы задать эти опции, на панели Configuration выберите Multitasking.
Дефект двойной разблокировки может указывать на ошибку кодирования. Возможно, вы хотели вызвать другую функцию разблокировки, чтобы закончить другой критический раздел. Возможно, вы преждевременно вызвали функцию разблокировки в первый раз, и только второй вызов указывает конец критического раздела.
Исправление зависит от первопричины дефекта.
Идентифицируйте каждый критический раздел кода, то есть раздел, который вы хотите выполнить как атомарный блок. Вызовите функцию блокировки в начале раздела. Только в конце раздела вызовите функцию разблокировки, которая соответствует функции блокировки. Удалите любой другой избыточный вызов функции разблокировки.
См. примеры исправлений ниже. Чтобы избежать проблемы, можно следовать практике вызова функций блокировки и разблокировки в том же модуле на том же уровне абстракции. Например, в этом примере func
вызывает функцию блокировки и разблокировки на том же уровне, но func2
не делает.
void func() { my_lock(); { // ... } my_unlock(); } void func2() { { my_lock(); // ... } my_unlock(); }
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
int global_var;
void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);
void task1(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
void task2(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
В этом примере, чтобы эмулировать поведение в многозадачном режиме, вы должны задать следующие опции:
Опция | Значение | |
---|---|---|
Configure multitasking manually | ||
Tasks |
| |
Critical section details | Starting routine | Ending routine |
BEGIN_CRITICAL_SECTION | END_CRITICAL_SECTION |
В командной строке можно использовать следующее:
polyspace-bug-finder -entry-points task1,task2 -critical-section-begin BEGIN_CRITICAL_SECTION:cs1 -critical-section-end END_CRITICAL_SECTION:cs1
task1
входит в критический раздел через вызов BEGIN_CRITICAL_SECTION();
. task1
оставляет критический раздел через вызов END_CRITICAL_SECTION();
. task1
вызывает END_CRITICAL_SECTION
снова без промежуточного вызова для BEGIN_CRITICAL_SECTION
.
Если вам нужен второй global_var+=1;
чтобы находиться вне критической секции, одной из возможных коррекций является удаление второго вызова на END_CRITICAL_SECTION
. Однако, если используются другие задачи global_var
, этот код может создать Data race
ошибка.
int global_var; void BEGIN_CRITICAL_SECTION(void); void END_CRITICAL_SECTION(void); void task1(void) { BEGIN_CRITICAL_SECTION(); global_var += 1; END_CRITICAL_SECTION(); global_var += 1; } void task2(void) { BEGIN_CRITICAL_SECTION(); global_var += 1; END_CRITICAL_SECTION(); }
Если вам нужен второй global_var+=1;
чтобы находиться внутри критической секции, одной из возможных коррекций является удаление первого вызова на END_CRITICAL_SECTION
.
int global_var; void BEGIN_CRITICAL_SECTION(void); void END_CRITICAL_SECTION(void); void task1(void) { BEGIN_CRITICAL_SECTION(); global_var += 1; global_var += 1; END_CRITICAL_SECTION(); } void task2(void) { BEGIN_CRITICAL_SECTION(); global_var += 1; END_CRITICAL_SECTION(); }
Если вам нужен второй global_var+=1;
чтобы находиться внутри критического раздела, другой возможной коррекцией является добавление другого вызова к BEGIN_CRITICAL_SECTION
.
int global_var; void BEGIN_CRITICAL_SECTION(void); void END_CRITICAL_SECTION(void); void task1(void) { BEGIN_CRITICAL_SECTION(); global_var += 1; END_CRITICAL_SECTION(); BEGIN_CRITICAL_SECTION(); global_var += 1; END_CRITICAL_SECTION(); } void task2(void) { BEGIN_CRITICAL_SECTION(); global_var += 1; END_CRITICAL_SECTION(); }
Группа: Rec. 14. Параллелизм (CON) |
[1] Это программное обеспечение было создано MathWorks, включающее фрагменты: «Сайт SEI CERT-C», © 2017 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.
ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОН И/ИЛИ ЕГО ИНЖЕНЕРНОГО ИНСТИТУТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ НА БАЗИСЕ «КАК ЕСТЬ». УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБОГО ВОПРОСА, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЮ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ КОММЕРЧЕСКОЙ ВЫГОДЫ, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.
Это программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллон или его Институтом программной инженерии.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.