The C/C++ languages are incredibly fast and versatile languages that offer the user an unprecedented level of control and performance over more abstract languages like Java and Python. This is why these languages continue to be so widely used despite the advent of “easier to program” interpreter based languages. However there are things that are hard to do in C/C++ that are generally much easier to do in other languages. Since the user is left with the responsibility to handle all allocated memory in these languages the assignation of thread-safe spaces can generally be complicated, especially when you need some variables to remain assigned across different program calls. Today I am going to talk about one important instance of this problem, specifically how to do cross-platform thread-safe static global variables in C/C++.
–
#ifndef THREAD_LOCAL_STORAGE_HPP_ #define THREAD_LOCAL_STORAGE_HPP_ #pragma once #include "storageUnits.hpp" class ThreadLocalStorage { public: ThreadLocalStorage(); ~ThreadLocalStorage(); void initThreadLocalStorage(); container* getMainContainer(); private: container mainContainer; }; #endif // THREAD_LOCAL_STORAGE_HPP_
#ifndef THREAD_LOCAL_STORAGE_WRAPPER_HPP_ #define THREAD_LOCAL_STORAGE_WRAPPER_HPP_ #pragma once #ifndef STORAGE_UNITS_HPP_ #include "storageUnits.hpp" #endif void initThreadLocalStorage(); container* getMainContainer(); #endif // THREAD_LOCAL_STORAGE_WRAPPER_HPP
#ifndef STORAGE_UNITS_HPP_ #define STORAGE_UNITS_HPP_ #pragma once typedef struct container_t { int a; int b; int c; double d; } container; #endif // STORAGE_UNITS_HPP_
–
Global static variables are important in programming because they allow us to save some information from the current program state in order to be used during future program calls. In trading this is necessary as we often want to preserve some information from the current trading system call to be used in the next one. For example if a system trades within an hour and we don’t want it to trade again till the next hour we want to save this information in a way that is easily accessible. Sure, we can save this information in a file and then read it during the next call but this method can be very inefficient and prone to problems. Sometimes this is also not practical as the information we want to save may be large in size – for example machine learning training examples – and therefore not easy to read-write on every library call.
The problem with doing static global variables in C/C++ is that these variables are not thread-safe. If you have your trading systems coded in a library and they all access the same static global variables then these variables will be overwritten by each library call since the library is using the same static memory space each time it is called in a different thread. This can easily cause bad behavior and lead to trading systems doing things you do not want them to. There are some easy solutions like Microsoft’s __declspec(thread) variable declaration – if you declare your static global variables in this manner they will use thread local storage – but this is not a general solution since it will only work in windows and has some important limitations.
–
#include "Precompiled.h" #include "ThreadLocalStorage.hpp" ThreadLocalStorage::ThreadLocalStorage() {} ThreadLocalStorage::~ThreadLocalStorage() {} void ThreadLocalStorage::initThreadLocalStorage() { mainContainer.a = 0; mainContainer.b = 0; mainContainer.c = 0; mainContainer.d = 1.5; } container* ThreadLocalStorage::getMainContainer() { return(&mainContainer); }
#include "Precompiled.hpp" #include "ThreadLocalStorageWrapper.hpp" #include "ThreadLocalStorage.hpp" namespace { boost::thread_specific_ptr<ThreadLocalStorage> ThreadLocalStoragePtr; } void initThreadLocalStorage() { if (ThreadLocalStoragePtr.get() == NULL){ ThreadLocalStoragePtr.reset(new ThreadLocalStorage()); ThreadLocalStoragePtr->initThreadLocalStorage(); } } container* getMainContainer() { return ThreadLocalStoragePtr->getMainContainer(); }
–
What to do then? Luckily the boost library offers a cross-platform thread local storage implementation that allows us to save any variables we want without limitations and then have them available on each library call. Different threads will all get different memory storage so the variable values will be independent in each case. To do this we simply need to create a thread storage class that defines some data storage container then we can create functions that populate this container in C++ and we can also easily create a wrapper in C that allows us to call these functions from this language.
After you implement the above code you can then either call the local storage class functions from C or C++. If you decide to call them from C++ you do not need the wrapper functions while if you want to call them from a C library you will need to use these functions in order to access the C++ code. The above example contains a storage unit with 4 variables, (a,b,c,d) three integers and a double, which can be accessed easily using a simple set of calls using the functions above. For example if I wanted to increase the value of “a” and decrease the value of “b” by 1 after each function call I would use the code below. Each thread would preserve its own values of “a” and “b”.
–
initThreadLocalStorage(); container* mainContainer; mainContainer = getMainContainer(); mainContainer->a += 1; mainContainer->b -= 1;
–
The above code examples show you how to do thread safe variable storage using the C++ boost library, which enables you to write thread-safe trading strategies that use the functional equivalent of global static variables without having to worry about multiple threads changing the value of the same memory spaces concurrently. If you would like to learn more about coding strategies in these languages and how you too can code and trade strategies that do things like fast machine learning using C please consider joining Asirikuy.com, a website filled with educational videos, trading systems, development and a sound, honest and transparent approach towards automated trading.strategies