• 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。

  • 相关阅读:
    【初学者入门C语言】之结构体(十一)
    LeetCode-1110. Delete Nodes And Return Forest [C++][Java]
    cordova Xcode打包ios以及发布流程(ionic3适用)
    Stability AI发布Stable Diffusion 3;谷歌修复Gemini大模型文生图多元化Bug;李一舟AI课遭下架
    十三、【分布式微服务企业快速架构】SpringCloud分布式、微服务、云架构之Eclipse 创建 XML 文件
    【TensorFlow2 之014】在 TF 2.0 中实现 LeNet-5
    3D孪生场景搭建:模型阵列摆放
    给定数组arr和整数k,返回第k小的数值对的解法
    神经网络(一)基本概念
    js数组去重的六种方法
  • 原文地址:https://blog.csdn.net/weixin_43973403/article/details/126167845