我们常用的进程(线程)间通信机制有管道,信号,消息队列,信号量,共享内存,socket等等,其中主要作为进程(线程)间通知/等待的有管道pipe和socketpair。线程还有特别的condition。
今天来看一个liunx较新的系统调用,它是从LINUX 2.6.27版本开始增加的,主要用于进程或者线程间的通信(如通知/等待机制的实现)。
它的标记可以有以下属性:
EFD_CLOECEX,EFD_NONBLOCK,EFD_SEMAPHORE。
在linux直到版本2.6.26,这个flags参数是没用的,必须指定为0。
它返回了一个引用eventfd object的描述符。这个描述符可以支持以下操作:
read:如果计数值counter的值不为0,读取成功,获得到该值。如果counter的值为0,非阻塞模式,会直接返回失败,并把errno的值指纹EINVAL。如果为阻塞模式,一直会阻塞到counter为非0位置。
write:会增加8字节的整数在计数器counter上,如果counter的值达到0xfffffffffffffffe时,就会阻塞。直到counter的值被read。阻塞和非阻塞情况同上面read一样。
close:这个操作不用说了。
#include
#include
#include
#include
#include
#define handle_error(msg) \
do{perror(msg); exit(EXIT_FAILURE);}while (0)
int main(int argc, char *argv[])
{
int efd, j;
uint64_t u;
ssize_t s;
if (argc < 2)
{
fprintf(stderr, "Usage: %s
exit(EXIT_FAILURE);
}
efd = eventfd(0, 0);
if (efd == -1)
{
handle_error("eventfd");
}
switch (fork())
{
case 0:
for (j = 1; j < argc; j++)
{
printf("Child writing %s to efd\n", argv[j]);
u = strtoull(argv[j], NULL, 0);
/* strtoull() allows various bases */
s = write(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
{
handle_error("write");
}
}
printf("Child completed write loop\n");
exit(EXIT_SUCCESS);
default:
sleep(2);
printf("Parent about to read\n");
s = read(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
{
handle_error("read");
}
printf("Parent read %llu (0x%llx) from efd\n",
(unsigned long long) u, (unsigned long long) u);
exit(EXIT_SUCCESS);
case -1:
handle_error("fork");
}
}
如果设置EFD_NONBLOCK 则为非阻塞,父进程读不到数据会直接返回,0 是阻塞的。