eventfd — это упрощенный системный вызов для межпроцессного взаимодействия, предоставляемый системой после Linux 2.6.22. Метод записи записывает 64-битное значение в пространство ядра, и для чтения этого значения также можно вызвать метод чтения.
Создать метод
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
При создании вы можете передать начальное значение счетчика initval. Второй параметр, flags, не используется в версиях до linux 2.6.26 и должен быть инициализирован равным 0, а в версиях после 2.6.27 используются флаги.
EFD_CLOEXEC (2.6.27~):
A copy of the file descriptor created by eventfd() is inherited by the child produced by fork(2). The duplicate file descriptor is associated with the same eventfd object. File descriptors created by eventfd() are preserved across execve(2), unless the close-on-exec flag has been set.
eventfd() вернет файловый дескриптор. Если процесс разветвлен, файловый дескриптор также будет скопирован. В это время будет несколько файловых дескрипторов, указывающих на один и тот же объект eventfd. Если установлен флаг EFD_CLOEXEC, когда дочерний процесс процесс выполняет exec, файловый дескриптор родительского процесса очищается.
EFD_NONBLOCK (2.6.27~):Буквально это означает, что если этот флаг не установлен, операция чтения будет заблокирована до тех пор, пока счетчик не получит значение. Если этот флаг не установлен, счетчик немедленно вернет -1 при отсутствии значения;
EFD_SEMAPHORE (2.6.30~):Этот флаг повлияет на операцию чтения.Подробности см. в пояснении к методу чтения.
предоставленный метод
read:Прочитать значение в счетчике
- Если значение счетчика больше 0
- Если флаг EFD_SEMAPHORE установлен, возвращается 1, а значение счетчика уменьшается на 1.
- Если флаг EFD_SEMAPHORE не установлен, возвращается значение счетчика, а счетчик устанавливается в 0.
- Если значение счетчика равно 0
- Если установлен флаг EFD_NONBLOCK, он напрямую возвращает -1.
- Если флаг EFD_NONBLOCK не установлен, он будет блокироваться до тех пор, пока значение счетчика не станет больше 0.
write:записать значение в счетчик
- Запись завершается успешно, если сумма записанных значений меньше 0xFFFFFFFFFFFFFFFE
- Если сумма записанных значений больше 0xFFFFFFFFFFFFFFFE
- Если установлен флаг EFD_NONBLOCK, он напрямую возвращает -1.
- Если флаг EFD_NONBLOCK не установлен, он будет заблокирован до тех пор, пока не будет выполнена операция чтения.
close:закрыть файловый дескриптор
Небольшая демонстрация
#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream>
int main() {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
eventfd_write(efd, 2);
eventfd_t count;
eventfd_read(efd, &count);
std::cout << count << std::endl;
close(efd);
}
В приведенной выше программе мы создаем eventfd, сохраняем его файловый дескриптор в efd, затем вызываем eventfd_write, чтобы записать число 2 в счетчик, затем вызываем eventfd_read, чтобы считать значение в счетчике и распечатывать обработку, и, наконец, закрываем eventfd. результат операции:
count=2
Читать и писать несколько раз
#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream>
int main() {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
eventfd_write(efd, 2);
eventfd_write(efd, 3);
eventfd_write(efd, 4);
eventfd_t count;
int read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
close(efd);
}
результат операции:
read_result=0
count=9
read_result=-1
count=9
Из текущих результатов мы видим, что когда eventfd_write вызывается несколько раз, счетчик продолжает накапливаться, но eventfd_read нужно вызвать только один раз, чтобы получить число в счетчике.Если eventfd_read вызывается снова, он вернет ошибку.
Роль флага EFD_NONBLOCK
#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream>
int main() {
int efd = eventfd(0, EFD_CLOEXEC);
eventfd_write(efd, 2);
eventfd_write(efd, 3);
eventfd_write(efd, 4);
eventfd_t count;
int read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
close(efd);
}
результат операции:
read_result=0
count=9
По сравнению с предыдущим результатом выполнения, возвращающим -1 напрямую, если флаг EFD_NONBLOCK удален, программа всегда будет блокироваться в методе eventfd_read, когда счетчик не имеет значения.
Роль флага EFD_SEMAPHORE
#include <sys/eventfd.h>
#include <unistd.h>
#include <iostream>
int main() {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE);
eventfd_write(efd, 2);
eventfd_t count;
int read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
read_result = eventfd_read(efd, &count);
std::cout << "read_result=" << read_result << std::endl;
std::cout << "count=" << count << std::endl;
close(efd);
}
результат операции:
read_result=0
count=1
read_result=0
count=1
read_result=-1
count=1
Видно, что после установки EFD_SEMAPHORE значение, считываемое каждый раз, равно 1, и счетчик также уменьшается на 1 после чтения.