eventfd

eventfd : 一个计数器,类似信号量;

eventfd 一般用于多线程,多进程,epoll

返回一个fd , 可读写;

write函数用于给计数器累加数值 , 例如:


    // 计数器初始化 : 0
    int _eventfd = eventfd(0,EFD_CLOEXEC);
     uint64_t t =2;
// 写入一个2, 则此时 计数器+= 2
     write(_eventfd,&t,sizeof(t));

// 再次写入一个2, 则此时 计数器是 4
     write(_eventfd,&t,sizeof(t));

 

read 函数用于计数器递减, 当eventfd 被write后, read被唤醒,并从计数器中获取值,直到递减到0,

如果eventfd是nonblock,则返回错误,否则阻塞在read;

在上面代码后添加一行:

    read(_eventfd,&t,sizeof(t));

    cout << t << endl;  // 4 , 此时计数器为 0,再次read将阻塞

read函数从当前的计数器中能拿多少就拿多少,

如果 写了1000次 2 ,则一次read 将读出2000;

 

一个多线程的例子:

int _eventfd;
int initEventFD(){
    //非阻塞
    _eventfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
    return _eventfd;
}
bool wakeup(){
    uint64_t t =2;
    //每次增加 2 
    ssize_t ret = write(_eventfd,&t,sizeof(t));
    return ret == sizeof(t);
}

void * write_thread(void *arg){
    sleep(1);
    //循环写入 1000次 2 , 计数器总计 2000
    for(int i = 0; i < 1000; ++i){
        wakeup();
    }
    cout << "write done !" << endl;
    return 0;
}
void * read_thread(void *ar){
    int c = 0;
    while(1){
        uint64_t t = 0;
        
        // 从计数器中获取值, 并递减,
        // 如果此时获取了 3, 则剩余的值为1997
        ssize_t ret = read(_eventfd,&t,sizeof(t));
        if(ret == sizeof(t)) {
            c+= t;
            cout << "read:" << t  << ", count:" << c<< endl;
            if(2000 == c) {
                cout << "read done " << endl;
                break;
            }
        }
    }
}
int main(int argc, char *argv[])
{

    initEventFD();//初始化
    pthread_t t1,t2;
    pthread_create(&t1,NULL,read_thread,NULL);
    pthread_create(&t2,NULL,write_thread,NULL);

    pthread_join(t1,0);
    pthread_join(t2,0);


    return 0;
}

输出:

read:6, count:1956
read:8, count:1964
read:6, count:1970
read:6, count:1976
read:8, count:1984
read:6, count:1990
read:8, count:1998
write done !read:2, count:2000
read done 

还有种输出:

write done !
read:2000, count:2000
read done 

结论: 你的输出极可能跟我的完全不一样,这是正常的.

第一种结果: 2个线程切换的挺平均, 因此read_thread每次都能读出一些数[ read 一次能读多少算多少,我的意思是减到0为止 ]

第2种 : write_thread 一次全执行了完了, read_thread后执行read , 一次性把所有全读取出来;

总之,不论你write了多少次,每次write的值是多少, read到最终总能读完所有的值,直到0   , 就一个计数器;

 

在初始化的时候还有个信号量的标志: EFD_SEMAPHORE

话说用于同步的semaphore 本来就是一个计数器 。 这个标志放在eventfd 中跟用于同步的semaphore类似,

每次递减 1 ;

上面的例子中, 可以看到每一次read 是有多少递减【拿】多少; 如果添加了这个标志,则每次递减 1;

例子:

int _eventfd;
int initEventFD(){
    _eventfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);
    return _eventfd;
}
int main(int argc, char *argv[])
{

    initEventFD();
    uint64_t t =2;
    write(_eventfd,&t,sizeof(t));
    read(_eventfd,&t,sizeof(t));
    cout << t << endl;    // 1
    read(_eventfd,&t,sizeof(t));
    cout << t << endl; //1
    return 0;
}

 

多线程的例子: 就不添加注释了, 跟上面的一个例子类似

int _eventfd;
int initEventFD(){
    _eventfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);
    return _eventfd;
}
bool wakeup(){
    uint64_t t =2;
    ssize_t ret = write(_eventfd,&t,sizeof(t));
    return ret == sizeof(t);
}
bool handleWakeup(){
    uint64_t t = 0;
    ssize_t ret = read(_eventfd,&t,sizeof(t));
    return ret == sizeof(t);
}
void * write_thread(void *arg){
    sleep(1);
    for(int i = 0; i < 1000; ++i){
        wakeup();
    }
    cout << "write done !" << endl;
    return 0;
}
void * read_thread(void *ar){
    int c = 0;
    while(1){
        uint64_t t = 0;
        ssize_t ret = read(_eventfd,&t,sizeof(t));
        if(ret == sizeof(t)) {
            c+= t;
            cout << "read:" << t  << ", count:" << c<< endl;
            if(2000 == c) {
                cout << "read done " << endl;
                break;
            }
        }
    }
}
int main(int argc, char *argv[])
{

    initEventFD();

    pthread_t t1,t2;
    pthread_create(&t1,NULL,read_thread,NULL);
    pthread_create(&t2,NULL,write_thread,NULL);


    pthread_join(t1,0);
    pthread_join(t2,0);


    return 0;
}

 

 输出:

read:1, count:1996
read:1, count:1997
read:1, count:1998
read:1, count:1999
read:1, count:2000
read done 

注意: 此时只有这样的输出是正确的, 因为信号量本身就是每次递减 1 , 所以每次 read 也只能获取 1;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值