boost库中thread多线程中的thread_specific_ptr

       大多数函数都不是可重入的。这也就是说在某一个线程已经调用了一个函数时,如果你再调用同一个函数,那么这样是不安全的。举例来说,std::strtok就是不可重入的,因为它使用静态变量来保存要被分割成符号的字符串。

函数原型:char *strtok(char *s,const char *delim)

函数功能:分解字符串为一组字符串,s为要分解的字符串,delim为分隔字符串

描述:strtok()用来将字符串分割成一个个片段,参数s指向将要被分隔的字符串,参数delim则为分隔字符串,当strtok()在参数s的字符串中发现到参数delim的分隔字符时,则会将该字符改为'\0'字符,在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL.每次调用成功则返回被分隔片段的指针。


#include <iostream>   
#include <cstring>   
using namespace std;   
int main()   
{   
 char sentence[]="This is a sentence with 7 tokens";  
  
 cout<<"The string to be tokenized is:\n"
  <<sentence<<"\n\nThe tokens are:\n\n"; 
   
 char *tokenPtr=strtok(sentence," "); 
   
 while(tokenPtr!=NULL) {   
  cout<<tokenPtr<<'\n';   
  tokenPtr=strtok(NULL," ");   
 } 
   
 cout<<"After strtok, sentence = "<<sentence<<endl;   
 return 0;   

/* 函数第一次调用需设置两个参数。第一次分割的结果,返回串中第一个 ',' 之前的字符串,也就是上面的程序第一次输出abc。   
 * 第二次调用该函数strtok(NULL,","),第一个参数设置为NULL。结果返回分割依据后面的字串,即第二次输出d。   
 * strtok是一个线程不安全的函数,因为它使用了静态分配的空间来存储被分割的字符串位置   
 * 线程安全的函数叫strtok_r,ca   
 * 运用strtok来判断ip或者mac的时候务必要先用其他的方法判断'.'或':'的个数,
 * 因为用strtok截断的话,比如:"192..168.0...8..."这个字符串,strtok只会截取四次,中间的...无论多少都会被当作一个key
 */      

上面内容引用自:https://blog.csdn.net/luciazzzz/article/details/38538033

       一个不可重入的函数通过连续的调用来保存静态变量或者是返回一个指向静态数据的指针,有两种方法可以让不可重用的函数变成可重用的函数。

       方法1:就是改变接口,用指针或引用代替原先使用静态数据的地方。比方说,POSIX定义了strok_r,std::strtok中的一个可重入的变量,它用一个额外的char**参数来代替静态数据。这种方法很简单,而且提供了可能的最佳效果。但是这样必须改变公共接口,也就意味着必须改代码。

        方法2:不用改变公有接口,而是用本地存储线程(Thread-Locally Storage)来代替静态数据(有时也被成为特殊线程存储,thread-specific storage)。

       Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。thread_specific_ptr线程局部存储的包装,它可用于封装线程独立的全局变量。每一个线程第一次使用这个智能指针的实例时,它的初值是NULL(所以必须要先检查这个它的值是否为空),在每个线程使用它之前需要new一个对象交给全局的threah_specific_ptr进行管理,当线程退出后,Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除,这样,各个线程就可以各自独立地访问这个全局变量的本地存储版本,线程之间就不会因为访问同一全局对象而引起资源竞争导致性能下降。而线程结束时,这个资源会被自动释放。

它可以应用在以下两种场景:

扫描二维码关注公众号,回复: 12249038 查看本文章

       1. 改编一个原本设计用于单线程的库接口,比如libc里的strtok函数。这种库一般隐含的使用一个全局变量,可以使用thread_specific_ptr控制全局变量,使其可用于多线程。
       2. 线程中使用了一系列的方法/函数,它们需要一个逻辑上的全局变量来共享数据,但实际上这个变量是线程独立的。

thread_specific_ptr代表了某个全局变量的本地存储,各个线程可以各自独立地通过它访问这个全局变量的本地副本,起到了井水不犯河水的效果。

使用boost::thread_specific_ptr的简单例子。

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/tss.hpp>
#include <iostream>
 
boost::mutex io_mutex;
boost::thread_specific_ptr<int> ptr;
 
struct count
{
        count(int id) : id(id) { }
        
        void operator()()
        {
                if (ptr.get() == 0)
                ptr.reset(new int(0));
                
                for (int i = 0; i < 10; ++i)
                {
                        (*ptr)++;
                        boost::mutex::scoped_lock
                        lock(io_mutex);
                        std::cout << id << ": "
                        << *ptr << std::endl;
                }
        }
        
        int id;
};
 
int main(int argc, char* argv[])
{
        boost::thread thrd1(count(1));
        boost::thread thrd2(count(2));
        thrd1.join();
        thrd2.join();
        return 0;
}

其中创建了两个线程来初始化本地存储线程,并有10次循环,每一次都会增加智能指针指向的值,并将其输出到std::cout上(由于std::cout是一个共享资源,所以通过互斥体进行同步)。main线程等待这两个线程结束后就退出。从这个例子输出可以明白的看出每个线程都处理属于自己的数据实例,尽管它们都是使用同一个boost::thread_specific_ptr。

参考:

https://blog.csdn.net/liujiayu2/article/details/50587084

https://blog.csdn.net/flyingleo1981/article/details/47083737

猜你喜欢

转载自blog.csdn.net/sunlin972913894/article/details/103647149