zoukankan      html  css  js  c++  java
  • fork安全的gettid高效实现

    进程有id,可以通过getpid()获得,线程也有id,但是glibc没有提供封装。需要自己发出系统调用。在关键路径,系统调用还是对性能有影响的。因此我们可以想到类似glibc对getpid做的cache化封装,用thread local的方式缓存每个线程的id,每个线程只有第一次调用gettid时才真正发起系统调用。

    #include <stdio.h>
    #include <syscall.h>
    #include <unistd.h>
    
    pid_t gettid() {
        static __thread pid_t cached_tid;
        if (cached_tid == 0) {
            cached_tid = syscall(SYS_gettid);
        }
        return cached_tid;
    }

    这段代码运行的很好,直到遇到fork。在我看来,fork是单线程时代的东西,与多线程格格不入,所以我们的代码中很少用到。其实这个问题除了对调用fork的线程来说是诡异的,因为fork时,其他线程是不会被fork的。但是对于主线程或者单线程程序,这个问题也还是存在的,存在就不爽。

    或许可以想到用pthread_atfork来做这个事情,其原型是这样的。

    int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

    文档说,child会在子进程中被调用。但是这里有个问题,cached_tid是线程局部变量,每个线程里的地址是不一样的,而child函数不支持传地址,难道我们要用动态生成代码(thunk)的猥琐方式?

    其实不必那么复杂,虽然glibc缓存了getpid,但是fork后getpid是会变的,因此我们可以在每次调用时再多比较一下pid是否发生了变化:

    pid_t gettid() {
        static __thread pid_t cached_pid;
        static __thread pid_t cached_tid;
        pid_t pid = getpid();
        if (cached_pid != pid || cached_tid == 0) {
            cached_pid == pid;
            cached_tid = syscall(SYS_gettid);
        }
        return cached_tid;
    }

    getpid是高效的,因此这段代码也是高校的。

    查阅glibc的源代码,getpid是从当前线程控制块里读取的,其实里面也有线程id,但是glibc却迟迟不肯提供封装,让我想起了一句话,程序员何苦为难程序员。

    测一下:

    int main() {
        printf("Parent: pid=%d, tid=%d
    ", getpid(), gettid());
        if (fork() == 0) {
            printf("Child: pid=%d, tid=%d
    ", getpid(), gettid());
        } else {
            printf("Parent after fork: pid=%d, tid=%d
    ", getpid(), gettid());
        }
    }

    Parent: pid=10776, tid=10776
    Parent after fork: pid=10776, tid=10776
    Child: pid=10777, tid=10777

    行为符合预期。

  • 相关阅读:
    转:Ubuntu12.04编译VLC,在linux上运行
    samba 安装运行
    设计模式学习笔记 1.factory 模式
    python之字符串的拼接总结
    str函数之不同变量之间如何连接,外加浮点运算注意事项
    python的安装以及前景
    input函数的运用和注意 小知识点
    mysql基础篇(上篇)
    接口测试基本安全
    jmeter接口自动化测试
  • 原文地址:https://www.cnblogs.com/chen3feng/p/4139730.html
Copyright © 2011-2022 走看看