Using thread-local storage to implement the log system under multithreading

Source: Internet
Author: User
Tags log4j

Http://www.ibm.com/developerworks/cn/linux/1310_qianbh_threadlog/index.html

Multithreaded programming has always been difficult, in the multi-threaded environment to implement the log system is a lot of programmers need to solve the problem. The concept and principle of thread-local storage are described in detail in this article, and the code example shows how to use thread-local storage to implement the log system under multi-threading.

Overview

In general, logs are required in the application to log the state of the program running so that the tracking of the later issues is targeted. In the design of the log system, there is usually a total log system to coordinate the settings of these logs such as location, output level and content. In multithreaded programming, when each thread needs to output a log, the design of the log system is more complex because it takes into account synchronization between threads.

In a single-threaded application, it is common to use a single log case to output important log information from the application running process, but in a multithreaded environment it is obviously not good because the logs printed by each thread are so intricate that the log files are not easy to read and trace. The better way is the main thread logs its own log, and each child thread records its own log separately. In order to preserve the simple and clear characteristics of log system in multi-threaded environment, this paper uses thread local variables to realize the log system under multi-threading. This ensures that each thread has its own clear log file, and that each thread has only one simple log case, making the log system simple, clear and efficient, and suitable for single-threaded and multithreaded applications.

The multi-threaded log system described in this paper is based on C + + and Boost library, which is very useful for the realization of log system in multi-threaded environment. If the original design of the log system does not consider the multi-threaded environment, with the development of the business needs to implement multi-threading, this method can easily transform the existing log system, so as to achieve multi-threaded log system, and this method can also keep the original log system business interface unchanged.

Background introduction

For the concept of thread-local storage, as the literal meaning is, each variable has a separate copy in each thread. By using thread-local storage technology, you can avoid synchronization problems between threads, and different threads can use different log settings. By using the smart pointer boost::thread_specific_ptr of the Boost library to access thread-local storage, each thread needs to initialize it the first time it attempts to acquire an instance of the smart pointer, and the thread-locally-stored data is freed by the Boost library when it is exited.

Advantages of using thread-local variables for multithreaded logging:

    1. Using static thread-local variables can easily implement thread-level single-instance logging systems;
    2. It is simple and convenient to access thread local storage through smart pointer boost::thread_specific_ptr;
    3. It is easy to use thread local variables to implement multi-threaded support for an existing single-instance log system without altering any of the original log interfaces;

Back to top of page

Logs for single-threaded environments

In general, the log class is implemented as a singleton, making it easy to invoke. For simplicity, the write operation for the log code in the example is printed directly to the console. The following is the initial definition of the Logger class:

Listing 1. Initial definition of the Logger class
Class Logger{private:    Logger () {}public:    static void Init (const std::string &name);    Static Logger *getinstance ();    void Write (const char *format, ...); Private:    static std::string ms_name;    Static Logger *ms_this_logger;};

The Init () function is used to set the name of the Logger. In real-world applications, you can set up configuration information for other Logger. In a single-threaded environment, each time the write () function is called, the log can be written.

Back to top of page

Logging for multithreaded environments

In the multi-threaded environment to implement the log system, the write operation must be locked, otherwise it will get chaotic output. The easy way to think of this is to maintain a list in the Logger class, store instances of Logger in all threads by name, and find each thread by name and use the thread's own unique Logger.

This is a bit like the implementation of log4j, the difference is that log4j all the Logger configuration in the configuration file, each Logger has a separate configuration. However, our Logger cannot implement this function because the configuration information is passed in at runtime and all Logger share the same configuration information.

Another big problem is that the declaration of getinstance () must be modified to include a parameter similar to the Logger name. This approach destroys the original API, and the existing code must be fully modified to support the new Logger class.

With thread-local storage, you can address the above two issues: each Logger configuration is thread independent and does not need to modify the declaration of getinstance (). The following is a declaration of the new Logger class, which uses the Boost Thread_specific_ptr class, which implements a cross-platform thread-local storage solution.

Listing 2. Logger class definitions using thread-local storage
Class Logger{private:    Logger () {}public:    static void Init (const std::string &name);    Static Logger *getinstance ();    void Write (const char *format, ...); Private:    static boost::thread_specific_ptr<std::string> ms_name;    Static boost::thread_specific_ptr<logger> Ms_this_logger;};

The code simply uses the Boost::thread_specific_ptr class to re-declare two static variables in the class, which are placed in the thread-local storage at run time.

Listing 3. Logger class implementation using thread-local variables
void Logger::init (const string &name) {    if (!name.empty ()) {        Ms_name.reset (new std::string (name));}    } Logger *logger::getinstance () {    if (ms_this_logger.get () = = NULL) {        ms_this_logger.reset (new Logger);    }    return Ms_this_logger.get ();}

In the implementation code, call the Reset () function of the Boost::thread_specific_ptr class to set the value. The following is a simple call code for the two Logger class, which creates two threads and sets the name of Logger in each thread:

Listing 4. Calling code for the Logger class
Class Thread{public:    Thread (const char *name): M_name (name) {}    void operator () ()    {/        * Set logger name in Thread *        /Logger::init (m_name);        /* Call getinstance () and Write () on other functions with thread-local enabled */        Logger *logger = logger::getinstance ();        for (int i = 0; i < 3; i++) {            logger->write ("Hello%d", i), #ifdef _win32 sleep (+),            #else            sleep (1); #en DIF        }    }private:    string m_name;}; int main () {    boost::thread T1 (thread ("name1"));    Boost::thread T2 (Thread ("name2"));    T1.join ();    T2.join ();    return 0;}

For the initial version of Logger, the output might be this:

Listing 5. Output from the initial version of the Logger class
#./logger[name1] Hello 0[name2] Hello 0[name2] Hello 1[name2] Hello 1[name2] Hello 2[name2] Hello 2

After the second thread has re-assigned the name, the first thread also receives an impact. For Logger using thread-local storage, the output is as follows:

Listing 6. Output of the Logger class using thread-local storage
#./logger2[name1] Hello 0[name2] Hello 0[name1] Hello 1[name2] Hello 1[name1] Hello 2[name2] Hello 2

The name variables in the two threads are independent of each other, and the correct values are printed separately.

Back to top of page

The implementation of the Boost library

How does the boost library implement thread-local storage? With the tracking code, the following are the call stacks for Windows and Linux platforms, respectively (based on version 1.43):

Listing 7. Boost::thread_specific_ptr the call stack under Windows
Boost::thread_specific_ptr::reset ()-  boost::d etail::set_tss_data ()-  boost::d etail::get_or_ Make_current_thread_data ()-  boost::d etail::get_current_thread_data ()-:  : TlsGetValue () # reference:# ${boost_src}/boost/thread/tss.hpp# ${boost_src}/lib/thread/src/win32/thread.cpp
Listing 8. Boost::thread_specific_ptr the call stack under Linux
Boost::thread_specific_ptr::reset ()-  boost::d etail::set_tss_data ()-  boost::d etail::add_new_ Tss_node ()-  boost::d etail::get_or_make_current_thread_data ()-  boost::d Etail::get_current_ Thread_data ()-  ::p thread_getspecific () # reference:# ${boost_src}/boost/thread/tss.hpp# ${boost_src}/lib/ Thread/src/pthread/thread.cpp

Under two platforms, the system API was called to implement thread-local storage. The relevant data structure can refer to the source code of boost.

Back to top of page

Summarize

This paper describes a simple multithreaded log system implemented by a thread-local storage variable using BOOST::THREAD_SPECIFIC_PTR. The content includes an overview of the log system, an introduction to the relevant background, code examples for the log system, and benefits, among others. The log system is a thread-level single-instance log system, with simple and efficient management, especially for the existing single-instance log system can not support multithreading provides a good way to reform, using thread-local storage variables can not change the original log system business interface.

Reference Learning
    • Introduction to TLS for thread-local storage: http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms686749 (v=vs.85). aspx
    • Principle and implementation of thread local storage TLS (thread local Storage)-Classification and principle: http://www.cppblog.com/Tim/archive/2012/07/04/181018.html
    • Boost::thread Brief analysis-thread-local storage and others (TLS,TSS): http://tieba.baidu.com/f?kz=52832822

Using thread-local storage to implement the log system under multithreading (GO)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.