CPU_SET(3)

ИМЯ
CPU_SET, CPU_CLR, CPU_ISSET, CPU_ZERO, CPU_COUNT, CPU_AND, CPU_OR, CPU_XOR, CPU_EQUAL, CPU_ALLOC, CPU_ALLOC_SIZE, CPU_FREE, CPU_SET_S, CPU_CLR_S, CPU_ISSET_S, CPU_ZERO_S, CPU_COUNT_S, CPU_AND_S, CPU_OR_S, CPU_XOR_S, CPU_EQUAL_S - макросы для работы с наборами ЦП

ОБЗОР
#define _GNU_SOURCE             /* Смотрите feature_test_macros(7) */
#include <sched.h>

void CPU_ZERO(cpu_set_t *set);

void CPU_SET(int cpu, cpu_set_t *set);
void CPU_CLR(int cpu, cpu_set_t *set);
int  CPU_ISSET(int cpu, cpu_set_t *set);

int  CPU_COUNT(cpu_set_t *set);

void CPU_AND(cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR(cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR(cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);

int  CPU_EQUAL(cpu_set_t *set1, cpu_set_t *set2);

cpu_set_t *CPU_ALLOC(int num_cpus);
void CPU_FREE(cpu_set_t *set);
size_t CPU_ALLOC_SIZE(int num_cpus);

void CPU_ZERO_S(size_t setsize, cpu_set_t *set);

void CPU_SET_S(int cpu, size_t setsize, cpu_set_t *set);
void CPU_CLR_S(int cpu, size_t setsize, cpu_set_t *set);
int  CPU_ISSET_S(int cpu, size_t setsize, cpu_set_t *set);

int  CPU_COUNT_S(size_t setsize, cpu_set_t *set);

void CPU_AND_S(size_t setsize, cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR_S(size_t setsize, cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR_S(size_t setsize, cpu_set_t *destset,
             cpu_set_t *srcset1, cpu_set_t *srcset2);

int  CPU_EQUAL_S(size_t setsize, cpu_set_t *set1, cpu_set_t *set2);

ОПИСАНИЕ
Набор ЦП описывается структурой данных cpu_set_t. Набор ЦП используется в sched_setaffinity(2) и подобных интерфейсах.

Тип данных cpu_set_t реализован в виде битовой маски. Однако структуру данных следует считать «чёрным ящиком»: все действия с наборами ЦП следует выполнять с помощью макросов, описанных на этой странице.

Для работы с набором ЦП set предоставляются следующие макросы:

CPU_ZERO()
    Очищает set, после этого он не содержит ЦП.

CPU_SET()
    Добавляет ЦП cpu в set.

CPU_CLR()
    Удаляет ЦП cpu из set.

CPU_ISSET()
    Проверяет, является ли ЦП cpu членом set.

CPU_COUNT()
    Возвращает количество ЦП в set.

Макросы, имеющие аргумент cpu, не вызывают побочных эффектов, все перечисленные выше макросы могут использовать аргумент более одного раза.

Значение первого ЦП системы в cpu обозначается как 0, значение следующего ЦП в cpu равно 1 и т. д. Нельзя предполагать о доступности каких-либо ЦП, или что набор ЦП непрерывен, так как ЦП могут динамически отключаться или вообще отсутствовать. Константой CPU_SETSIZE (в настоящее время 1024) задаётся значение на 1 большее, чем максимальный номер ЦП, который можно хранить в cpu_set_t.

Следующие макросы выполняют логические операции над наборами ЦП:

CPU_AND()
    Сохраняет пересечение наборов srcset1 и srcset2 в destset (который может быть одним из наборов-аргументов).

CPU_OR()
    Сохраняет объединение наборов srcset1 и srcset2 в destset (который может быть одним из наборов-аргументов).

CPU_XOR()
    Сохраняет результат XOR наборов srcset1 и srcset2 в destset (который может быть одним из наборов-аргументов). Операция XOR возвращает набор из ЦП, которые есть в одном из srcset1 или srcset2, но не в обоих одновременно.

CPU_EQUAL()
    Проверяет, что два набора ЦП содержат одинаковые ЦП.

  Динамически изменяемые наборы ЦП
Так как некоторым приложениям может потребоваться наборы ЦП динамически изменяемых размеров (например, для выделения наборов больше, чем определено стандартным типом данных cpu_set_t), glibc предоставляет набор макросов для этого.

Следующие макросы используются для выделения и удаления наборов ЦП:

CPU_ALLOC()
    Выделяет набор ЦП, достаточный для хранения ЦП в диапазоне от 0 до num_cpus-1.

CPU_ALLOC_SIZE()
    Возвращает размер набора ЦП в байтах, который необходим для хранения ЦП в диапазоне от 0 до num_cpus-1. Данный макрос предоставляет значение, которое можно использовать в аргументе setsize в макросах CPU_*_S(), описанных далее.

CPU_FREE()
    Освобождает набор ЦП, выделенный ранее с помощью CPU_ALLOC().

Макросы, чьи имена заканчиваются на «_S», аналогичны макросам с тем же именем без суффикса. Эти макросы выполняют те же задачи что и их аналоги, но они работают с динамически выделяемыми наборами ЦП, размер которых равен setsize байт.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Макросы CPU_ISSET() и CPU_ISSET_S() возвращают ненулевое значение, если cpu есть в set; в противном случае возвращается 0.

Макросы CPU_COUNT() и CPU_COUNT_S() возвращают количество ЦП в set.

Макросы CPU_EQUAL() и CPU_EQUAL_S() возвращают ненулевое значение, если два набора ЦП одинаковы; в противном случае возвращается 0.

При успешном выполнении макрос CPU_ALLOC() возвращает указатель, при ошибке возвращается NULL (ошибки те же, что и у malloc(3)).

Макрос CPU_ALLOC_SIZE() возвращает количество байт, требуемое для хранения набора ЦП указанных элементов.

Остальные функции не возвращают никаких значений.

ВЕРСИИ
Макросы CPU_ZERO(), CPU_SET(), CPU_CLR() и CPU_ISSET() добавлены в glibc версии 2.3.3.

Макрос CPU_COUNT() впервые появилась в glibc версии 2.6.

Макросы CPU_AND(), CPU_OR(), CPU_XOR(), CPU_EQUAL(), CPU_ALLOC(), CPU_ALLOC_SIZE(), CPU_FREE(), CPU_ZERO_S(), CPU_SET_S(), CPU_CLR_S(), CPU_ISSET_S(), CPU_AND_S(), CPU_OR_S(), CPU_XOR_S() и CPU_EQUAL_S() впервые появились в glibc версии 2.7.

СООТВЕТСТВИЕ СТАНДАРТАМ
Данные интерфейсы есть только в Linux.

ЗАМЕЧАНИЯ
Для создания копии набора ЦП используйте memcpy(3).

Так как наборы ЦП это битовые маски, выделяемые в единицах длинных слов, реальное количество ЦП в динамически выделенном наборе ЦП будет округлено до следующего кратного sizeof(unsigned long). Приложение должно считать содержимое этих дополнительных бит неопределённым.

Несмотря на похожесть имён, заметим, что константа CPU_SETSIZE определяет количество ЦП в типе данных cpu_set_t (то есть, эффективное количество битов в битовой маске), в то время как аргумент setsize макросов CPU_*_S() — это размер в байтах.

Типы данных параметров и возвращаемых значений, показанных в ОБЗОРЕ — подсказки, что ожидается в каждом случае. Однако так как эти интерфейсы реализованы как макросы, компилятор не обязательно поймает все ошибки приведения типов, если вы нарушите предположения.

ДЕФЕКТЫ
На 32-разрядных платформах в glibc 2.8 и ранее CPU_ALLOC () выделяет вдвое больше пространства, как требуется, и CPU_ALLOC_SIZE() возвращает значение вдвое большее, чем должно. Эта ошибка не должна влиять на семантику программы, но приводит к трате впустую памяти и менее эффективной работе макросов для динамически выделяемых наборов ЦП. Эти ошибки исправлены в glibc версии 2.9.

ПРИМЕР
Следующая программа показывает использование некоторых макросов, работающих с динамически выделяемыми наборами ЦП.

    #define _GNU_SOURCE
    #include <sched.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <assert.h>
    int
    main(int argc, char *argv[])
    {
        cpu_set_t *cpusetp;
        size_t size;
        int num_cpus, cpu;
        if (argc < 2) {
            fprintf(stderr, "Использование: %s <количество-ЦП>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        num_cpus = atoi(argv[1]);
        cpusetp = CPU_ALLOC(num_cpus);
        if (cpusetp == NULL) {
            perror("CPU_ALLOC");
            exit(EXIT_FAILURE);
        }
        size = CPU_ALLOC_SIZE(num_cpus);
        CPU_ZERO_S(size, cpusetp);
        for (cpu = 0; cpu < num_cpus; cpu += 2)
            CPU_SET_S(cpu, size, cpusetp);
        printf("CPU_COUNT() набора:    %d\n", CPU_COUNT_S(size, cpusetp));
        CPU_FREE(cpusetp);
        exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
sched_setaffinity(2), pthread_attr_setaffinity_np(3), pthread_setaffinity_np(3), cpuset(7)