核心内容摘要
探索数字影海:中文无码电影网站资源获取指南
线程数据控制在实际的开发中经常遇到各种情况的数据处理。
最典型的就是开发者经常遇到的线程数据共享的情况不管是利用互斥变量还是其它形式的同步机制可以保证线程间数据交互的安全性。
但有一种情况下恰恰是需要各个线程需要自己处理自己的数据。
对于开发者来说最简单的方式就是定义一个数据然后与线程绑定。
但这种方式有不少缺点除了编程的复杂性外也需要开发者显式的控制相关线程与数据的绑定依赖关系。
这在线程的中引入了不必要的麻烦。
在Windows平台和Posix库中都引入了线程局部存储变量。
后来在C11中也引入了类似的相关机制并提供了thread_local关键字。
它从系统层面上解决了开发者相关的自定义处理让相关代码变得更容易理解和维护。
线程局部存储线程局部存储即TLSThread-Local Storage。
它可以让每个线程拥有独立的变量副本从而隔离多线程间数据的同步问题。
可以这样理解TLS的变量相对每个线程是一个深拷贝每个线程虽然都拥有相同的变量名字但其实是完全独立存在的不会因为某个线程修改自己的此名称变量导致其它线程中的此名称变量的改变。
举一个不太恰当的例子比如有多个人多个线程在打卡机前写考勤以前只能一个一个人来需要同步而后来使用了软件打考勤每个人打开自己的考勤软件直接打卡写考勤就可以了局部存储考勤。
TLS的应用其实并没想象的那么多但又是不可或缺的。
常见的应用场景有线程需要独立处理各自的数据或变量如独立随机数和计数器等线程需要独立处理异常和错误线程需要处理各自独立的缓存或临时数据总之只要开发者需要在线程中对同类型的数据进行独立处理都可以考虑使用线程的局部存储。
底层机制不同的平台对线程的局部存储有着不同的实现方式下面就简单分析一下在Windows平台和Linux平台上的实现Windows平台它分为两种实现情况一种是静态的TLS需要编译器层级的支持实现的方法如下__declspec(thread)inttlsDemo;其主要原理为编译器在编译的.tls段中为每个TLS变量分配地址空间并在线程启动时由系统处理相关的TLS块然后线程中可以通过TEBThread Environment Block对相关变量进行操作管理。
有静态就会有动态这就需要使用相关的API来操作了在Windows上提供了下面的API来进行动态的TLS创建//get valueint*value(int*)HeapAlloc(GetProcessHeap(),0,sizeof(int));*value100;//alloc tls varDWORD tlsDemoTlsAlloc();//set value to tlsvalueTlsSetValue(tlsDemo,value);//get tslvaluevoid*tlsValueTlsGetValue(tlsDemo);TlsFree(tlsDemo);动态TLS使用API创建它通过接口分配独立的TLS索引并进行相关的TLS值的读写操作并提供了相关的释放回收函数。
在每个进程中会维护着一组的TLS索引一般是64个。
然后进程中的线程可以独立的通过索引来找到各自的局部存储位置其实就是把开发者的绑定转移到了系统中绑定。
动态和静态的TLS各有优势前者更灵活方便可以动态的处理上下文的数据而后者则由编译器和系统自动控制使用起来更简单。
需要哪种就使用哪种混合使用也不是不行。
Linux平台Linux本身并没有线程这个概念不过在Posix库提供了类似的实现。
其基本的实现方式也有两种,先介绍静态实现//ELF格式下的支持__threadinttls_demo0;这是一种早期的实现其实现机制与Windows平台类似将相关的数据变量分配到ELF的.tdata初始化和 .tbss未初始化中然后通过TCBThread Control Block对数据线程局部存储变量进行操作管理。
在Linux平台上可以使用readelf等工具对相关的数据段进行访问查看。
其动态创建的方法也是通过相关的API来实现pthread_key_tkey;pthread_key_create(key,free);int*valuemalloc(sizeof(int));*value100;pthread_setspecific(key,value);int*tls_value(int*)pthread_getspecific(key);free(tls_value);pthread_key_delete(key);C STL在C11后STL提供了thread_local关键字来支持线程的局部存储。
应该了解的是这种底层实现机制标准库一般都是依赖于系统平台本身的实现否则无法和系统契合不能保证相关的安全处理机制。
换句话说C11中的thread_local底层就是根据不同的平台调用不同平台的相关线程局部存储的处理机制来实现的。
在Linux平台一般是通过Posix和Glibc来提供TLS的实现在Windows平台使用上面提到的相关动、静态 方式实现。
更具体的底层实现代码可参看glibc中的源码中的代码。
由上面的分析可以看出静态的TLS一般是由编译器和系统共同处理的由系统和运行时库进行共同管理的内存空间其生命周期与线程同时存在。
而动态的TLS其生命周期由开发者自行控制。
另外线程的局部存储一般不会太大和栈空间的限制一样磢在KB级别这需要开发者引起注意。
具体应用一般来说标准库有的都会推荐使用标准库的实现看一下C11 thread_local的示例#includeiostream#includemutex#includestring#includethreadthread_localunsignedintrage1;std::mutex cout_mutex;voidincrease_rage(conststd::stringthread_name){rage;// modifying outside a lock is okay; this is a thread-local variablestd::lock_guardstd::mutexlock(cout_mutex);std::coutRage counter for thread_name: rage\n;}intmain(){std::threada(increase_rage,a),b(increase_rage,b);{std::lock_guardstd::mutexlock(cout_mutex);std::coutRage counter for main: rage\n;}a.join();b.join();}thread_local更类似于上面分析的静态实现它不需要开发者主动去参与管理这一点和栈有点类似。
五、
总结其实越是分析C相关的知识就会发现其内部体系也是一步步的逐渐建立起来的。
这也符合人们的普遍认知大厦不是一夜建成的。
所以标准在不断的迭代不断的完善旧的体系创建新的体系并在合适的时机升级成新的体系。