CERT C: Rec. CON05-C

Не выполняйте операции, которые могут блокироваться при содержании блокировки

Описание

Управляйте определением

Не выполняйте операции, которые могут блокироваться при содержании блокировки. [1]

Примеры

развернуть все

Описание

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

Средство проверки рассматривает вызовы этих функций как потенциально длинные:

  • Функции, которые получают доступ к сети, такой как recv

  • Системный вызов функционирует, такие как fork, pipe и system

  • Функции для операций I/O, таких как getchar и scanf

  • Обработка файла функционирует, такие как fopen, remove и lstat

  • Манипуляция с директориями функционирует, такие как mkdir и rmdir

Средство проверки автоматически обнаруживает определенные примитивы, которые содержат и выпускают блокировку, например, pthread_mutex_lock и pthread_mutex_unlock. Для полного списка примитивов, которые автоматически обнаруживаются, смотрите Автоматическое обнаружение Создания Потока и Критического Раздела в Polyspace.

Риск

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

Фиксация

Выполните блокирующуюся операцию прежде, чем содержать блокировку или после выпуска блокировки.

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

Пример - Сетевые Операции ввода-вывода с recv, В то время как Фиксатор

#include <pthread.h>
#include <sys/socket.h>

pthread_mutexattr_t attr;
pthread_mutex_t mutex;
 
void thread_foo(void *ptr) {
  unsigned int num;
  int result;
  int sock;
 
  /* sock is a connected TCP socket */
 
  if ((result = pthread_mutex_lock(&mutex)) != 0) {
    /* Handle Error */
  }
 
  if ((result = recv(sock, (void *)&num, sizeof(unsigned int), 0)) < 0) {
    /* Handle Error */
  }
 
  /* ... */
 
  if ((result = pthread_mutex_unlock(&mutex)) != 0) {
    /* Handle Error */
  }
}
 
int main() {
  pthread_t thread;
  int result;
 
  if ((result = pthread_mutexattr_settype(
      &attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
    /* Handle Error */
  }
 
  if ((result = pthread_mutex_init(&mutex, &attr)) != 0) {
    /* Handle Error */
  }
 
  if (pthread_create(&thread, NULL,(void*(*)(void*))& thread_foo, NULL) != 0) {
    /* Handle Error */
  }
 
  /* ... */
 
  pthread_join(thread, NULL);
 
  if ((result = pthread_mutex_destroy(&mutex)) != 0) {
    /* Handle Error */
  }
 
  return 0;
}

В этом примере, в каждом потоке, созданном с pthread_create, функциональный thread_foo выполняет операцию сети I/O с recv после получения блокировки с pthread_mutex_lock. Другие потоки с помощью той же переменной mutex блокировки должны ожидать операции, чтобы завершиться и блокировка, чтобы стать доступными.

Исправление — выполняет блокирующуюся операцию прежде, чем получить блокировку

Одно возможное исправление должно вызвать recv прежде, чем получить блокировку.

#include <pthread.h>
#include <sys/socket.h>

pthread_mutexattr_t attr;
pthread_mutex_t mutex;
 
void thread_foo(void *ptr) {
  unsigned int num;
  int result;
  int sock;
 
  /* sock is a connected TCP socket */
  if ((result = recv(sock, (void *)&num, sizeof(unsigned int), 0)) < 0) {
    /* Handle Error */
  }
  
  if ((result = pthread_mutex_lock(&mutex)) != 0) {
    /* Handle Error */
  }
 
    /* ... */
 
  if ((result = pthread_mutex_unlock(&mutex)) != 0) {
    /* Handle Error */
  }
}
 
int main() {
  pthread_t thread;
  int result;
 
  if ((result = pthread_mutexattr_settype(
      &attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
    /* Handle Error */
  }
 
  if ((result = pthread_mutex_init(&mutex, &attr)) != 0) {
    /* Handle Error */
  }
 
  if (pthread_create(&thread, NULL,(void*(*)(void*))& thread_foo, NULL) != 0) {
    /* Handle Error */
  }
 
  /* ... */
 
  pthread_join(thread, NULL);
 
  if ((result = pthread_mutex_destroy(&mutex)) != 0) {
    /* Handle Error */
  }
 
  return 0;
}

Проверяйте информацию

Группа: Rec. 14. Параллелизм (CON)

Введенный в R2019a


[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.