Описание
Операция 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;
}