Thread_specific_ptr in thread multithreading in boost library

       Most functions are not reentrant. This means that when a thread has already called a function, it is not safe if you call the same function again. For example, std::strtok is not reentrant because it uses static variables to store the string to be divided into symbols.

Function prototype: char *strtok(char *s,const char *delim)

Function: decompose a string into a set of strings, s is the string to be decomposed, and delim is the delimited string

Description: strtok() is used to divide the string into fragments, the parameter s points to the string to be separated, the parameter delim is the delimited string, when strtok() finds the parameter delim in the string of the parameter s When separating the character, the character will be changed to'\0' character. In the first call, strtok() must be given to the parameter s string, and subsequent calls will set the parameter s to NULL. Each call succeeds It returns the pointer of the separated fragment.


#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;   

/* Two parameters need to be set for the first call of the function. The result of the first split, returns the string before the first',' in the string, which is the first time the above program outputs abc.   
 * The function strtok(NULL,",") is called for the second time, and the first parameter is set to NULL. The result is returned to the string following the division basis, which is the second output d.   
 * strtok is a thread-unsafe function, because it uses statically allocated space to store the position of the divided string   
 * The thread-safe function is called strtok_r,ca   
 * When using strtok to determine ip or mac, be sure to use others first The method of judging the number of'.' or':',
 * Because using strtok truncated, such as: "192..168.0...8..." this string, strtok will only intercept four times, the middle. .. No matter how many will be treated as a key
 */      

The above content is quoted from: https://blog.csdn.net/luciazzzz/article/details/38538033

       A non-reentrant function saves static variables or returns a pointer to static data through successive calls. There are two ways to make a non-reusable function a reusable function.

       Method 1: Change the interface and replace the original static data with pointers or references. For example, POSIX defines strok_r, a reentrant variable in std::strtok, which uses an additional char** parameter to replace static data. This method is simple and provides the best possible results. But this must change the public interface, which means that the code must be changed.

        Method 2: Do not change the public interface, but use Thread-Locally Storage instead of static data (sometimes called thread-specific storage).

       The Boost thread library provides a smart pointer boost::thread_specific_ptr to access the local storage thread. thread_specific_ptr is a wrapper for thread local storage, which can be used to wrap thread-independent global variables. When each thread uses the instance of this smart pointer for the first time, its initial value is NULL (so you must first check whether its value is empty). Before each thread uses it, a new object needs to be handed over to the global threah_specific_ptr is managed. When the thread exits, the Boost thread library guarantees that the data saved in the local storage thread will be cleared after the thread ends. In this way, each thread can independently access the local storage version of this global variable. Will not cause resource competition due to access to the same global object and cause performance degradation. When the thread ends, this resource will be automatically released.

It can be applied in the following two scenarios:

       1. Adapt a library interface originally designed for single thread, such as the strtok function in libc. This kind of library generally implicitly uses a global variable, and thread_specific_ptr can be used to control the global variable so that it can be used for multiple threads.
       2. A series of methods/functions are used in the thread, they need a logical global variable to share data, but in fact this variable is thread independent.

thread_specific_ptr represents the local storage of a global variable, and each thread can independently access the local copy of this global variable through it, which has the effect of not damaging the river.

A simple example of using 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;
}

Two threads are created to initialize the local storage thread, and there are 10 cycles. Each time the value pointed to by the smart pointer is increased and output to std::cout (since std::cout is a shared resource, so Synchronization through mutexes). The main thread waits for the end of these two threads and then exits. From the output of this example, it can be clearly seen that each thread processes its own data instance, even though they all use the same boost::thread_specific_ptr.

reference:

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

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

Guess you like

Origin blog.csdn.net/sunlin972913894/article/details/103647149