Наконец, вы можете удалить элементы из дерева и, на системах GLIBC, удалить само дерево целиком:
void *tdelete(const void *key, void **rootp,
int (*compare)(const void*, const void*));
/* Расширение GLIBC, в POSIX нет: */
void tdestroy(void *root, void (*free_node)(void *nodep));
Аргументы для tdelete()
те же, что и для tsearch()
: ключ, адрес корня дерева и функция сравнения. Если в дереве найден данный элемент, он удаляется, и tdelete()
возвращает указатель на NULL
. С этим поведением следует обращаться в своем коде осмотрительно, если вам нужен первоначальный удаляемый элемент, например, для освобождения занимаемой им памяти.
struct employee *е, key; /* Объявления переменных */
void *vp, *root;
/* ...заполнить ключ для удаляемого из дерева элемента... */
vp = tfind(&key, root, emp_name_id_compare); /* Найти удаляемый элемент */
if (vp != NULL) {
e = *((struct employee**)vp); /* Преобразовать указатель */
free(e); /* Освободить память */
}
(void)tdelete(&key, &root, emp_name_id_compare); /* Теперь удалить его из дерева */
Хотя это и не указано в справочных страницах или стандарте POSIX, под GNU/Linux, если вы удаляете элемент, хранящийся в корневой вершине, возвращается значение новой корневой вершины. Для переносимого кода не следует полагаться на это поведение
Функция tdestroy()
является расширением GLIBC. Она позволяет удалить дерево целиком. Первый аргумент является корнем дерева. Второй является указателем на функцию, которая освобождает NULL
! Это приведет к аварийной ситуации.
• Иногда бывает необходимо выделить память, выровненную по определенной границе. Это осуществляет posix_memalign()
. Ее возвращаемое значение отличается от большинства из рассмотренных в данной книге функций. memalign()
также выделяет выровненную память, но не все системы поддерживают освобождение памяти с помощью free()
.
• Блокирование файлов с помощью fcntl()
предусматривает блокировку диапазонов, вплоть до блокирования отдельных байтов в файле. Блокировки чтения предотвращают запись в заблокированную область, а блокировки записи предотвращают чтение и запись другими процессами в заблокированную область. По умолчанию используется вспомогательная блокировка, и POSIX стандартизует лишь вспомогательную блокировку. Большинство современных систем Unix поддерживают обязательную блокировку, используя для файла бит setgid прав доступа, а также возможные дополнительные опции монтирования файловой системы.
• GNU/Linux функция lockf()
действует в качестве оболочки вокруг блокировки POSIX с помощью fcntl()
; блокировки функции BSD flock()
совершенно независимы от блокировок fcntl()
. Блокировки BSD flock()
используются лишь для всего файла в целом и не работают на удаленных файловых системах. По этим причинам использование блокировки flock()
не рекомендуется.
• gettimeofday
() получает время дня в виде пар (секунды, микросекунды) в struct timeval
. Эти значения используются utimes()
для обновления времени доступа и модификации файла. Системные вызовы gettimer()
и settimer()
используют пары struct timeva
l в struct itimerval
для создания интервальных таймеров — сигнальных часов, которые «срабатывают» в установленное время и продолжают срабатывать впоследствии с заданным интервалом. Три различных таймера обеспечивают контроль тех состояний, когда таймер продолжает действовать.
• Функция nanosleep()
использует struct timespec
, которая указывает время в секундах и наносекундах, чтобы приостановить выполнение процесса в течение определенного интервала времени. У нее есть удачная особенность не взаимодействовать вообще с механизмами сигналов.