linux网络编程的若干问题

在linux下每一个进程都一个进程id,类型pid_t,可以由getpid()获取。
POSIX线程也有线程id,类型pthread_t,可以由pthread_self()获取,线程id由线程库维护。 但是各个进程独立,所以会有不同进程中线程号相同节的情况。
那么这样就会存在一个问题,我的进程p1中的线程pt1要与进程p2中的线程pt2通信怎么办,进程id不可以,线程id又可能重复,所以这里会有一个真实的线程id唯一标识,tid。glibc没有实现gettid的函数,所以我们可以通过linux下的系统调用syscall(SYS_gettid)来获得。
syscall() 执行一个系统调用,根据指定的参数number和所有系统调用的汇编语言接口来确定调用哪个系统调用。

gcc __thread关键字
Thread Local Storage
线程局部存储(tls)是一种机制,通过这一机制分配的变量,每个当前线程有一个该变量的实例.

gcc用于实现tls的运行时模型最初来自于IA-64处理器的ABI,但以后被用到其它处理器上。它需要链接器(ld),动态连接器(ld.so)和系统库(libc.so,libpthread.so)的全力支持.因此它不是到处可用的。

在用户层,用一个新的存储类型关键字:__thread表示这一扩展。例如:

__thread int i;

extern __thread struct state s;

static __thread char *p;

__thread限定符(specifier)可以单独使用,也可带有extern或static限定符,但不能带有其它存储类型的限定符。

__thread可用于全局的静态文件作用域,静态函数作用域或一个类中的静态数据成员。不能用于块作用域,自动或非静态数据成员。

当应用address-of操作符于一个线程局部存储变量时,它被在运行时求值,返回该变量当前线程实例的地址。这样得到的地址可以被其它任何线程使用。当一个线程终止时,任何该线程中的线程局部存储变量都不再有效。静态初始化不会涉及到任何线程局部存储变量的地址。

在c++中,如果一个线程局部存储变量有一个初始化器,它必须是常量表达式。

获取当前线程ID的方法

#include <unistd.h>
#include <sys/syscall.h>
#define gettid() syscall(__NR_gettid)
 
pid_t tid=gettid(); //current thread id
pid_t pid=getpid(); //current process id

系统调用次数会影响程序的性能。如果有多个类需要查看当前线程ID,首先想到的方法就是定义个全局变量,但是在多线程中就会导致频繁调用系统函数降低性能,而且定义全局变量总是一个坏想法。
考虑到这些问题,关键字__thread可以很好地帮助我们解决问题。

善用__thread关键字
__thread是GCC内置的线程局部存储设施(thread local storage)。它的实现非常高效。__thread变量是每个线程有一份独立实体,各个线程的变量值互不干扰。除了这个主要用途,它还可以修饰那些“值可能会变,带有全局性,但是又不值得用全局锁保护”的变量。

需要注意的是它的使用规则:只能用于修饰POD类型(Plain old data structure),不能修饰class类型,因为无法自动调用构造函数和析构函数。__thread可以用于修饰全局变量、函数内的静态变量,但是不能用于修饰函数的局部变量或者class的普通成员变量。另外,__thread变量的初始化只能用编译期常量。

猜你喜欢

转载自blog.csdn.net/weixin_39116058/article/details/88600538