May 21, 2020

​Did you already hear ​a ​programmer ask this question:

​Hey ! Why ​are we using a special library ​for logging ? We could use cout/printf instead and implement our ​personal header on it.

This is not a stupid question. I saw many young programmer ignoring why a special library is used to log in a multi threaded ​application.

It is perfect to introduce to you one of the fundamentals concerning the multi-threading in C/C++.
You see, the standard outputs as "cout" and "printf" are competitive between threads. Although C++11 standard gives some guarantees for the completeness.
However the performance and format are compromised. We can get this kind of issue with a simple test. Let's ​go with the following code:

#include <iostream>
#include <thread>

class ThreadManager
{
public:
    ThreadManager();
    ~ThreadManager();
    void createThread(size_t number);
    static void myThreadFunction(size_t assignedNumber);
private:
    std::thread threadObject;
    size_t threadNumber;
};
#include <ThreadManager.h>

static const size_t NUMBER_OF_THREAD_CREATED = 5;
static const size_t NUMBER_OF_LOGS_PER_THREADS = 10;

ThreadManager::ThreadManager() :
    threadNumber(-1)
{
}

ThreadManager::~ThreadManager()
{
    threadObject.join();
}

void ThreadManager::createThread(size_t number)
{
    threadNumber = number;
    threadObject = std::thread(myThreadFunction, number);
}

void ThreadManager::myThreadFunction(size_t assignedNumber)
{
    for (size_t i = 0; i < NUMBER_OF_LOGS_PER_THREADS; ++i)
    {
        std::cout << "Thread created: " << assignedNumber << " - Log number "
        << i << std::endl;
    }
}

int main()
{
    // Initialize threads
    ThreadManager threadManagerList[NUMBER_OF_THREAD_CREATED];
    std::cout << "Program running !" << std::endl;

    for(size_t i = 0; i < NUMBER_OF_THREAD_CREATED; ++i)
    {
        threadManagerList[i].createThread(i);
    }

    std::cout << "All thread created !" << std::endl;

    return 0;
}

​This code is pretty simple: The main will create 5 threads with 10 logs per threads... Let see a piece of the output:

​Here we are exactly in the main issue: The format is not complete - Prints between thread 0 and thread 1 are melted.
There are several way to resolve this:

  • ​1 - Create a home made logger protected by Mutex (or MsgQueue usage).
  • ​2 - Use a third party library (for instance, log4cxx, boost or glog).
  • ​3 - For Real-Time environment, a hardware logger could be necessary.

​Simple resolution with "glog"

​I'll feature to you a simple resolution of this ​with a third party library used for logging, glog:
https://github.com/google/glog

Now, let's modify this code with a basic implementation of Glog:

ThreadManager::ThreadManager() :
    threadNumber(-1)
{
}

ThreadManager::~ThreadManager()
{
    threadObject.join();
}

void ThreadManager::createThread(size_t number)
{
    threadNumber = number;
    threadObject = std::thread(myThreadFunction, number);
}

void ThreadManager::myThreadFunction(size_t assignedNumber)
{
    for (size_t i = 0; i < NUMBER_OF_LOGS_PER_THREADS; ++i)
    {
        LOG(INFO) << "Thread created: " << assignedNumber << " - Log number "
        << i;
    }
}

int main()
{
    // Initialize glog
    google::InitGoogleLogging("");
    // Initialize threads
    ThreadManager threadManagerList[NUMBER_OF_THREAD_CREATED];
    LOG(INFO) << "Program running !";

    for(size_t i = 0; i < NUMBER_OF_THREAD_CREATED; ++i)
    {
        threadManagerList[i].createThread(i);
    }

    LOG(INFO) << "All thread created !";

    return 0;
}

​Now, let's take a look to this new output (with the environment variable "GLOG_logtostderr=1" set) !

​It looks good now ! Thanks to this kind of Library, the logger is now thread-safe and able to support new functionalities easily like:

  1. Timestamp
  2. Filename
  3. ​Line
  4. Thread number

For multithreading ​purpose, those kind of libraries are ​useful for logging or analysis.

About the author 

Axel Fortun

​Developer specialized in Linux environment and embedded systems.
​Knowledge in multiple languages as C/C++, Java, Python​ and AngularJs.
​Working as Software developer since 2014 with a beginning in the car industry​ and then in ​medical systems.