This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Support for std::thread and other synchronization primitives, e.g. std::mutex...

I would like to know if any of the compilers/libraries for Cortex-M support the std::thread type (from the <thread> header) or if there is any plan to support that in the near future. I am interested in both Keil MDK / DS-5 or GCC for ARM. Thank you!

  • First of all, let me tell you that threads should be discussed separately to mutexes, but some of my remarks below apply to both... std::mutex is generally not a problem here.

    The most important thing here is that - unfortunately - C++11 standard for multithreaded applications just doesn't fit the world of microcontrollers at all... There is absolutely nothing you can do about that, but - from the point of view of a ARM Cortex-M microcontroller, things like std::thread are completely unusable.

    The root cause of the problem is that C++ committee decided that std::thread is only a VERY thin wrapper for the facilities provided by an operating system. That's why this object effectively doesn't support anything else than creation, joining and detachment. So when constructing the thread you can ONLY pass it the info about the executed function and the arguments. There is absolutely no way to configure the most important thing on a microcontroller, which is the size of stack... std::thread was created for the world of systems with MMU (Memory Management Unit), which gives you - among other things - virtual memory. With virtual memory inability to configure stack size is not a problem at all, as whenever the thread used all that was allocated, the system can give it another page or two, and thanks to MMU the operation of "resizing" the stack is seamless. Nothing like that is possible for a chip like ARM Cortex-M...

    Any attempt to overcome this issue is either non-standard (modifying std::thread) or very hard to use (function to set "default size of stack", which would have to be used right before constructor and from within critical section). Unless you have a lot of memory and wish to have every single stack in the system be of the same size - in that case it could work too.

    The second important thing is that in a MCU you probably want to have *real-time* operating system, which requires things like priorities and scheduling policy to be configurable. These are also left out, and the only thing you can use to set that is std::thread::native_handle(). This interface looks like a kludge here - you effectively have to use the functions of the underlying OS anyway...

    Obviously there are other problems here, like the fact that whole STL is built on assumption you use C++ exceptions to report errors and that many things are allocated from the heap. These are not so important here, as with enough memory they become just slight inconveniences.

    As I'm a big fan of C++11 myself, I once also wanted to have std::thread and friends on microcontroller, but after thinking about that longer I just came to the above conclusions.

    So generally I would say that that there's absolutely nothing preventing you to have std::thread and stuff on you microcontrollers, but it would all be just a nice tech demo, with usability close to zero...

    I really wanted to use all the nice things of the C++11 in the microcontroller. This is perfectly possible, but with a slightly different API, which would allow you to set the size of stack before starting the thread. That's why I'm currently working on a C++ RTOS for microcontrollers (in C++11) - http://distortos.org/ - which tries to follow all the good things in the standard. For example this is what you can do with it:

     

    #include "distortos/board/leds.hpp"
    
    #include "distortos/chip/ChipOutputPin.hpp"
    
    #include "distortos/StaticThread.hpp"
    #include "distortos/ThisThread.hpp"
    
    void blinkFunction(distortos::devices::OutputPin& led, std::chrono::milliseconds on,
    		std::chrono::milliseconds off)
    {
    	while (1)
    	{
    		led.set(true);
    		distortos::ThisThread::sleepFor(on);
    		led.set(false);
    		distortos::ThisThread::sleepFor(off);
    	}
    }
    
    int main()
    {
    	auto thread = distortos::makeAndStartStaticThread<1024>(1, blinkFunction,
    			std::ref(distortos::board::leds[0]), std::chrono::milliseconds{100},
    			std::chrono::milliseconds{900});
    	thread.join();
    }

    This creates a thread with low priority (1), 1024 bytes of stack, which blinks the LED by turning it on for 100ms and then turning it off for 900ms.

    This is a working project, not a tech demo (;

  • Actually with some small modifications to the GCC headers, this can be done on top of FreeRTOS as an example (it provides the threading). 

    Here's an article;

    https://www.researchgate.net/publication/282350782_C14_concurrency_on_ARM_Cortex-M_using_FreeRTOS_and_GCC

    ..and the code;

    https://github.com/microHAL/microhal

    You don't need all of that though, there's about half a dozen headers you need to modify to put in place a FreeRTOS based version of gthread, which is the C++ OS portability layer. It works well.