• eventfd和__thread的应用


    eventfd和__thread的应用

    muduo可以通过设置线程数量来决定开几个EventLoop,一个EventLoop有多个channel。当channel上有事件发生时,就应该在他所属的EventLoop上执行。
    比如在一个mainReactor一个subReactor的情况下,mainReactor监听到一个新连接,要把这个新连接派发给subReactor。而subReactor可能大部分的时间都在loop(epoll_wait)阻塞的状态,mainReactor不能强把这个新连接塞给subReactor的Poller,这不合理也不安全,这就需要唤醒阻塞的subReactor,并且让它自己来把这个新连接添加到它的Poller上。
    如何确定这个新连接是在它所属的EventLoop上处理的呢?
    one loop per thread,我们可以通过系统中唯一的线程ID来确认他们所属的loop。

    eventfd唤醒subReactor

    在这里插入图片描述
    eventfd用于创建一个专门唤醒事件的一个文件描述符。
    当有新连接到来时,如果subReactor还在阻塞,不能一直等到subReactor阻塞返回,应该把它唤醒,立刻处理新连接。
    我们可以让subReactor监听一个eventfd,在需要唤醒时往eventfd里写一个字节,这样subReactor就可以从loop(epoll_wait)阻塞状态返回了。
    用传统的pipe也可以实现,但eventfd可以更高效的唤醒,因为他不必管理缓冲区。

    巧用__thread关键字

    __thread是GCC内置的线程局部存储设施(thread local storage)。可以用来修饰POD类型,不能修饰class类型,因为无法自动调用构造和析构函数。
    __thread可以用于修饰全局变量、函数内的静态变量,但是不能用于修饰函数的局部变量会在class的普通成员变量。另外,__thread变量的初始化只能用编译期常量。例如:

    __thread string t_obj1("hello");   //错误,不能调用对象的构造函数
    __thread string* t_obj2 = new string;	//错误,初始化必须用编译器常量
    __thread string* t_obj3 = NULL;		//正确,但是需要手工初始化并销毁对象
    
    • 1
    • 2
    • 3

    __thread修饰的变量每个线程都有一份独立实体,各个线程的变量值互不干扰。

    获取当前线程id接口:
    CurrentThread.h

    #pragma once 
    
    #include 
    #include 
    
    namespace CurrentThread
    {
        extern __thread int t_cachedTid;
    
        void cacheTid();
    
        inline int tid()
        {
            if(__builtin_expect(t_cachedTid == 0, 0))
            {
                cacheTid();
            }
            return t_cachedTid;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    CurrentThread.cc

    #include "CurrentThread.h"
    
    namespace CurrentThread
    {
        __thread int t_cachedTid = 0;
    
        void cacheTid()
        {
            if(t_cachedTid == 0)
            {
                //通过Linux系统调用,获取当前线程的pid值
                t_cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    因为每个线程都有__thread修饰变量的一份独立实体,在线程调用CurrentThread::tid,获取的一定是当前线程的id。

  • 相关阅读:
    使用Python制作内马尔的胜利之舞代码版
    短视频矩阵系统软件源码
    Blackmagic Design DaVinci Resolve Studio18(达芬奇调色剪辑)mac/win中文版
    vue pc商城---最终篇
    xml元素值需要保留space
    数据结构 第四章:串
    【网页设计】期末大作业html+css(音乐网站)
    golang常用库之-配置文件解析 spf13/viper包 | 解析&加载配置
    计算机毕设(附源码)JAVA-SSM基于的优质房源房租管理系统
    vue项目+xlsx+xlsx-style 实现table导出为excel的功能——技能提升
  • 原文地址:https://blog.csdn.net/weixin_43973403/article/details/126167845