Операция Blocking, в то время как фиксатор

Задача выполняет долгую операцию при содержании блокировки

Описание

Операция 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 не ожидает сообщения, чтобы стать доступным.

Примеры

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

#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;
}

Информация о результате

Группа: параллелизм
Язык: C | C++
Значение по умолчанию: 'off'
Синтаксис командной строки: BLOCKING_WHILE_LOCKED
Влияние: низко
ID CWE: 667

Введенный в R2018b